Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, March 19, 2014 12:36 PM
I'm using MVC Foolproof Validation on a project for RequiredIfTrue on a model item. Similar to others, I experienced the NOTIMPLEMENTEDEXCEPTION that apparently is Entity Framework not playing nice. Following the solution in this thread I was able to overcome the error by rebuilding the DLL with the new code. The problem is, now the RequiredIfTrue no longer works, and the other Required validation items display the error message and then submit the form anyway. (The Required validation works BEFORE you click on the radio button choice for payment options)
My model is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using Foolproof;
namespace Golf_2014.Models
{
public class Order
{
[Key]
[DataMemberAttribute()]
[HiddenInput(DisplayValue = false)]
public string OrderNumber
{ get; set; }
[DataMemberAttribute()]
[HiddenInput(DisplayValue = false)]
public DateTime OrderDate { get; set; }
public string Organization { get; set; }
public string Title { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[Display(Name = "Address")]
public string Address { get; set; }
[Display(Name = "Address 2")]
public string Address_2 { get; set; }
[Required]
[Display(Name = "City")]
public string City { get; set; }
[Required]
[Display(Name = "State")]
public string State { get; set; }
[Display(Name = "Card Expiration")]
public string ExpirationMonth { get; set; }
public string ExpirationYear { get; set; }
[Required]
[Display(Name = "Zip Code")]
public string Zip { get; set; }
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[Display(Name = "Phone Number")]
[RegularExpression(@"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", ErrorMessage = "Not a valid number")]
public string Phone { get; set; }
public bool? PaidInFull { get; set; }
public int? Quantity { get; set; }
public string Cart { get; set; }
public bool CreditCard { get; set; }
public bool Invoice { get; set; }
[DataMemberAttribute()]
[HiddenInput(DisplayValue = false)]
public int Total { get; set; }
[RequiredIfTrue("PaidInFull")]
[Display(Name = "Type of Credit Card")]
public string CardType { get; set; }
[RequiredIfTrue("PaidInFull")]
[Display(Name = "Name on Card")]
public string NameOnCard { get; set; }
[RequiredIfTrue("PaidInFull")]
[StringLength(16)]
[Display(Name = "Card Number")]
public string CardNumber { get; set; }
[RequiredIfTrue("PaidInFull")]
[Display(Name = "Security Code")]
public string SecurityCode { get; set; }
public bool Foundation { get; set; }
public string Password
{
get
{
string _pass = Membership.GeneratePassword(10, 2);
return _pass;
}
set { }
}
public virtual ICollection<Players> PlayerListings { get; set; }
public Order()
{
PlayerListings = new HashSet<Players>();
}
// function to generate the order number for ALL orders
public string GenerateOrderNumber()
{
DateTime date = DateTime.Now;
string dayString = String.Format("{0:u}", date);
// remove dashes, colon and spaces from datetime string
dayString = dayString.Replace("-", "");
dayString = dayString.Replace(":", "");
dayString = dayString.Replace(" ", "");
string transID = "";
int r, k;
// length of the random character ID to build
int idLength = 5;
char[] upperCase = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
char[] lowerCase = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
char[] numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
Random rand = new Random();
for (int iterator = 0; iterator < idLength; iterator++)
{
r = rand.Next(3);
if (r == 0)
{
k = rand.Next(0, 25);
transID += upperCase[k];
}
else if (r == 1)
{
k = rand.Next(0, 25);
transID += lowerCase[k];
}
else if (r == 2)
{
k = rand.Next(0, 9);
transID += numbers[k];
}
}
// add the random characters to the daytime string (14 char length) and ends with Z
transID += dayString;
return transID;
}
}
}
and the view is
@model Golf_2014.Models.Order
@using Golf_2014.ViewModels
@{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Golf Registration";
DropDownLists ddl = new DropDownLists();
string ordNumb = Model.GenerateOrderNumber();
}
<section>
<h4 class="featurette-heading">Golf and Sponsorship Registration</h4>
@using (Html.BeginForm("Register", "Home", FormMethod.Post, new { @id = "regform" }))
{
@Html.ValidationSummary(true)
@Html.EditorFor(model => model.OrderNumber)
@Html.EditorFor(model => model.OrderDate)
@Html.EditorFor(model => model.Total)
@Html.Hidden("PlayerNumber")
// Organization
<div class="editor-label">
@Html.LabelFor(model => model.Organization)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Organization)
</div>
// Title
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Title, ddl.ProperTitles, new { @id = "titles" })
</div>
// First name
<div class="editor-label">
@Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FirstName)
@Html.ValidationMessageFor(model => model.FirstName)
</div>
// Last name
<div class="editor-label">
@Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
// Address
<div class="editor-label">
@Html.LabelFor(model => model.Address)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Address)
@Html.ValidationMessageFor(model => model.Address)
</div>
// Address 2
<div class="editor-label">
@Html.LabelFor(model => model.Address_2)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Address_2)
</div>
// City
<div class="editor-label">
@Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.City)
@Html.ValidationMessageFor(model => model.City)
</div>
// State
<div class="editor-label">
@Html.LabelFor(model => model.State)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.State, ddl.StateNames, new { @id = "state" })
@Html.ValidationMessageFor(model => model.State)
</div>
// Zip code
<div class="editor-label">
@Html.LabelFor(model => model.Zip)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Zip)
@Html.ValidationMessageFor(model => model.Zip)
</div>
// Phone
<div class="editor-label">
@Html.LabelFor(model => model.Phone)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Phone)
@Html.ValidationMessageFor(model => model.Phone)
</div>
// Email
<div class="editor-label">
@Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email)
</div>
// Product Choices - Shopping Cart
<div class="editor-label">
@Html.Label("Purchase")
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Cart, ddl.CartItems, new { @id = "cart" })
</div>
<div class="qty">
<div class="editor-label">
@Html.Label("Quantity")
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.Quantity, null, new { @style = "width:30px;" })
</div>
</div>
// Payment Method
<div class="editor-label">
@Html.Label("Payment Method")
</div>
<div class="editor-field">
@Html.RadioButtonFor(model => model.PaidInFull, "true", new { id = "creditcardpayment"}) Credit Card
@Html.RadioButtonFor(model => model.PaidInFull, "false", new { id = "invoiceneeded", @style = "margin-left:30px;"}) Invoice Me
</div>
<div class="ccblock" style="display:none;">
@* Name on Card*@
<div class="editor-label">
@Html.LabelFor(model => model.NameOnCard)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.NameOnCard)
</div>
@*Type of Card*@
<div class="editor-label">
@Html.LabelFor(model => model.CardType)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.CardType, ddl.CardNames, new { @id = "scrap" })
</div>
@*Credit Card Number*@
<div class="editor-label">
@Html.LabelFor(model => model.CardNumber)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.CardNumber)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ExpirationMonth)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.ExpirationMonth, ddl.Months, new { @id = "months" })
@Html.DropDownListFor(model => model.ExpirationYear, ddl.Years, new { @id = "year" })
</div>
<div class="editor-label">
@Html.LabelFor(model => model.SecurityCode)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.SecurityCode, null, new { @style = "width:50px;" })
</div>
</div>
<!-- end ccblock -->
<div class="editor-label">
<button type="submit" id="regButton" class="btn btn-success">Submit</button>
</div>
}
</section>
@section scripty{
<script type="text/javascript">
// display the credit card information fields once they have selected form of payment radio button
$('.editor-field > input:radio').click(function() {
if ($('#creditcardpayment').is(':checked')) {
$('.ccblock').toggle('display');
} else {
$('.ccblock').css('display', 'none');
}
});
// display the quantity div once they have chosen their product
// text field for quantity displays on Hole sponsorships, player, and foursomes
$('#cart').change(function () {
var choice = $('#cart').val();
var cartitem = choice.slice(0, (choice.indexOf(" ") != -1 ? choice.indexOf(" ") : choice.length));
switch (cartitem.toLowerCase()) {
case "hole":
$('.qty').toggle(true);
break;
case "individual":
$('.qty').toggle(true);
break;
case "foursome":
$('.qty').toggle(true);
break;
default:
$('.qty').toggle(false);
$('.qty').attr('value', '1');
break;
}
});
// add mask to phone input field
$(function($){
$('#Phone').mask("(999) 999-9999");
});
// Total the cart items
$('#regButton').click(function () {
var total;
var price;
// value of the cart drop-down
var choice = $('#cart').val();
// convert the value into something lower case and just the initial word for comparison
var cartitem = choice.slice(0, (choice.indexOf(" ") != -1 ? choice.indexOf(" ") : choice.length));
var players = 0;
//value of quantity text field
var quantity = parseInt($('#Quantity').val(), 10);
if (isNaN(quantity) || quantity == "") {
quantity = 1;
}
$('#Quantity').attr('value', quantity);
switch (cartitem.toLowerCase()) {
case "individual":
price = 150;
players = quantity;
break;
case "foursome":
price = 550;
players = (4 * quantity);
break;
case "premier":
price = 7500;
players = 8;
break;
case "event":
price = 5000;
players = 8;
break;
case "cart":
price = 3000;
players = 4;
break;
case "beverage":
price = 2500;
players = 4;
break;
case "lunch":
price = 2000;
players = 4;
break;
case "putting":
price = 1500;
players = 4;
break;
case "hole":
price = 350;
break;
default:
price = 0;
break;
}
total = price * quantity;
$('#Total').attr('value', total);
$('#PlayerNumber').attr('value', players);
if (!$(this).valid()) {
return false;
}
else {
return true;
}
});
</script>
}
Is this an issue where the foolproof is a lost cause or do I have alternatives? I'd like to keep the validation that they enter CC information if they choose credit card payment, but the foolproof seems to not be working. The author admits the program wasn't written with EF in mind, and apparently hasn't worked out a solution in the two years that the issue was posted.
Any solutions?
All replies (12)
Wednesday, March 19, 2014 5:15 PM âś…Answered
Thinking about it, can you also post the order that the javascript scripts are loaded (from the browser) as this script relies on jQuery and jQuery.validate being loaded before any of the foolproof stuff.
Wednesday, March 19, 2014 12:55 PM
I'm hesitant to knock ANY Open Source project, as they all represent more of someone's blood, seat and tears than I've been able to muster up. But, that being said, I'd suggest you look more closely at FluentValidation. It seems more active, has more downloads, and has a more visible community of users. On top of that, it's dead-simple to use.
Wednesday, March 19, 2014 12:59 PM
Just to set your expectations, I have never used this foolproof plugin, so there's a good chance I won't be able to sort anything out.
Now that's out of the way, What do you mean RequiredIfTrue no longer works. In the browser or on server? If browser, can you let us see the rendered html from the browser?
Have you checked your browser developer tools for javascript errors? What version of jquery are you using?
Wednesday, March 19, 2014 1:17 PM
The RequiredIfTrue is on the PaidInFull attribute. Basically it requires those credit card related fields if they click the radio button for that payment option. The browser does give the following errors (firebug):
TypeError: b is undefined
http://localhost:59255/Scripts/mvcfoolproof.unobtrusive.min.js
Line 1
and
ReferenceError: Sys is not defined
http://localhost:59255/Scripts/MvcFoolproofValidation.min.js
Line 1
I'm using jquery 1.10.2.
Wednesday, March 19, 2014 1:30 PM
I'd suggest downgrading to a version of jquery that was around the last time that plugin was modified: 1.7.2 would fit that criteria.
You can get it from the CDN: http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.js
next can you swap out the developer version of the foolproof validation .js files (e.g. the ones without .min in the name)
Also would still be good to see the rendered HTML, specifically the fields in question PaidInFull and credit card fields.
Wednesday, March 19, 2014 2:56 PM
Ok, I have switched to 1.7.2 on the jquery version and swapped out the minified versions to the js files. The errors in Firebug are now:
TypeError: $Unob is undefined
http://localhost:59255/Scripts/MvcFoolproofValidation.js
Line 68
which translates to code for both errors
Sys.Mvc.ValidatorRegistry.validators["is"] = function (rule) {
return function (value, context) {
var operator = rule.ValidationParameters["operator"];
var passOnNull = rule.ValidationParameters["passonnull"];
var dependentProperty = foolproof.getId(context.fieldContext.elements[0], rule.ValidationParameters["dependentproperty"]);
var dependentValue = document.getElementById(dependentProperty).value;
if (foolproof.is(value, operator, dependentValue, passOnNull))
return true;
return rule.ErrorMessage;
};
};
and
ReferenceError: Sys is not defined
http://localhost:59255/Scripts/MvcFoolproofValidation.js
Line 68
The rendered HTML for the PaidInFull and associated credit card fields are:
<div class="editor-field">
<input type="radio" value="true" name="PaidInFull" id="creditcardpayment"> Credit Card
<input type="radio" value="false" style="margin-left:30px;" name="PaidInFull" id="invoiceneeded"> Invoice Me
</div>
<div style="display:none;" class="ccblock">
<div class="editor-label">
<label for="NameOnCard">Name on Card</label>
</div>
<div class="editor-field">
<input type="text" value="" name="NameOnCard" id="NameOnCard" data-val-requiredif-operator="EqualTo" data-val-requiredif-dependentvalue="True" data-val-requiredif-dependentproperty="PaidInFull" data-val-requiredif="Name on Card is required due to PaidInFull being equal to True" data-val="true" class="text-box single-line">
</div>
<div class="editor-label">
<label for="CardType">Type of Credit Card</label>
</div>
<div class="editor-field">
<select name="CardType" id="scrap" data-val-requiredif-operator="EqualTo" data-val-requiredif-dependentvalue="True" data-val-requiredif-dependentproperty="PaidInFull" data-val-requiredif="Type of Credit Card is required due to PaidInFull being equal to True" data-val="true"><option value="" selected="selected">Choose Your Card Type</option>
<option value="Mastercard">Mastercard</option>
<option value="Visa">Visa</option>
<option value="American Express">American Express</option>
</select>
</div>
<div class="editor-label">
<label for="CardNumber">Card Number</label>
</div>
<div class="editor-field">
<input type="text" value="" name="CardNumber" id="CardNumber" data-val-requiredif-operator="EqualTo" data-val-requiredif-dependentvalue="True" data-val-requiredif-dependentproperty="PaidInFull" data-val-requiredif="Card Number is required due to PaidInFull being equal to True" data-val-length-max="16" data-val-length="The field Card Number must be a string with a maximum length of 16." data-val="true" class="text-box single-line">
</div>
<div class="editor-label">
<label for="ExpirationMonth">Card Expiration</label>
</div>
<div class="editor-field">
<select name="ExpirationMonth" id="months"><option value="01">January</option>
<option value="02">February</option>
<option value="03">March</option>
<option value="04">April</option>
<option value="05">May</option>
<option value="06">June</option>
<option value="07">July</option>
<option value="08">August</option>
<option value="09">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
<select name="ExpirationYear" id="year"><option value="2014">2014</option>
<option value="2015">2015</option>
<option value="2016">2016</option>
<option value="2017">2017</option>
<option value="2018">2018</option>
<option value="2019">2019</option>
<option value="2020">2020</option>
</select>
</div>
<div class="editor-label">
<label for="SecurityCode">Security Code</label>
</div>
<div class="editor-field">
<input type="text" value="" style="width:50px;" name="SecurityCode" id="SecurityCode" data-val-requiredif-operator="EqualTo" data-val-requiredif-dependentvalue="True" data-val-requiredif-dependentproperty="PaidInFull" data-val-requiredif="Security Code is required due to PaidInFull being equal to True" data-val="true">
</div>
</div>
When they click the radio button, it displays the CC info if that is their choice. Otherwise it just submits the form.
Wednesday, March 19, 2014 3:14 PM
Before I download the code and try to recreate your scenario, can you just have a quick look and maybe test something for me:
You're not loading all 3 scripts are you? You are only supposed to load:
mvcfoolproof.unobtrusive.js AND (MvcFoolproofJQueryValidation.js OR MvcFoolproofValidation.js)
If you are loading all 3 scripts, can you stop loading the MvcFoolproofValidation.js script.
If you are just using mvcfoolproof.unobtrusive.js and MvcFoolproofValidation.js, can you swap to mvcfoolproof.unobtrusive.js and MvcFoolproofJQueryValidation.js
Wednesday, March 19, 2014 3:23 PM
I'm just using mvcfoolproof.unobtrusive.js and MvcFoolproofJQueryValidation.js (after your pionting out I don't need all three) and it is still operating in the same manner. The error console is showing:
TypeError: $Unob is undefined
http://localhost:59255/Scripts/mvcfoolproof.unobtrusive.js
Line 153
var $Unob = $.validator.unobtrusive;
Line 153 -> $Unob.adapters.add("requiredif", ["dependentproperty", "dependentvalue", "operator", "pattern"], function (options) {
var value = {
dependentproperty: options.params.dependentproperty,
dependentvalue: options.params.dependentvalue,
operator: options.params.operator,
pattern: options.params.pattern
};
setValidationValues(options, "requiredif", value);
});
The validation also doesn't display the error messages on the credit card fields when left blank.
Wednesday, March 19, 2014 3:30 PM
In mvcfoolproof.unobtrusive.js change that line its pointing at (153) to be
var $Unob = jQuery.validator.unobtrusive;
rather than $.validator.unobtrusive;
Wednesday, March 19, 2014 5:03 PM
so once I put jquery in, it said it didn't recognize jquery (Jquery is not defined). So I started look at the load sequence for js to see if jquery wasn't getting loaded for the validor file to use. Well, the code was a 304 stauts on the NET tab of firebug (Love Firebug). So I started using a local version (1.7.1) of jquery instead of the CDN and converted the var back to $.validator.unobtrusive. This put the errors back to:
TypeError: $Unob is undefined
http://localhost:59255/Scripts/mvcfoolproof.unobtrusive.js
Line 153
Wednesday, March 19, 2014 5:11 PM
Make sure jquery is loading but keep the edit in the foolproof script. If you see all the other calls in the mvcfoolproof.unobtrusive.js, they all use the jQuery reference rather than the $ reference.
Make sure it is typed as jQuery too, not Jquery/JQuery/jquery...
Monday, March 24, 2014 12:55 PM
Ok. After a quick review of the JS files included, it seems there was two copies of the validate.js file being linked in the page. This was obviously disrupting the foolproof js execution, so I have a working copy now.
Thanks Russ!