I have an object inside an IEnumerable of my model class, the rendered HTML looks like
<input data-val="true" data-val-number="The field money must be a number." data-val-remote="'money' is invalid." data-val-remote-additionalfields="*.money" data-val-remote-url="/RemoteValidator/ValidateMoney" data-val-required="The money field is required." id="BudgetDetails_0__BudgetData_Money" name="BudgetDetails[0].BudgetData.Money" type="text" value="100" />
<span class="field-validation-valid" data-valmsg-for="BudgetDetails[0].BudgetData.Money" data-valmsg-replace="true"></span>
The model classes look like
public class MyViewModel
{
public IEnumerable<Budget> BudgetDetails { get; set; }
}
public class Budget
{
public int SomeIdentifier { get; set; }
public BudgetValues BudgetData { get; set; }
}
public class BudgetValues
{
[Remote("ValidateMoney", "RemoteValidator")]
public decimal? Money { get; set; }
// other properties
}
View is
#model DictionaryAndRemote.Models.MyViewModel
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
<script src="#Url.Content("~/Scripts/jquery-1.5.1.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
</head>
<body>
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.BudgetDetails)
<br />
<input type="submit" value="Submit user Data" />
}
</body>
</html>
The edit template Views\Shared\EditorTemplates\Budget.cshtml is
#model DictionaryAndRemote.Models.Budget
<div id="#Model.SomeIdentifier.ToString()">
<div>
#Html.TextBoxFor(x => x.BudgetData.Money)
#Html.ValidationMessageFor(x => x.BudgetData.Money)
</div>
</div>
The UI will trigger Ajax call http://localhost:4276/RemoteValidator/ValidateMoney?BudgetDetails%5B0%5D.BudgetData.Money=500 but unfortunately routing table is unable to match the request to my action method
public ActionResult ValidateMoney(decimal money)
{
return Json("I will always fail you.", JsonRequestBehavior.AllowGet);
}
Because the parameter name does not match. Since is is inside an IEnumerable the parameter name is even dynamic BudgetDetails[0].BudgetData.Money, BudgetDetails[1].BudgetData.Moneyand so on.
Of course I always can tweak action medhod to be
public ActionResult ValidateMoney()
{
string parameter = Request.QueryString.ToString();
return Json("I will always fail you.", JsonRequestBehavior.AllowGet);
}
And use very primitive way to parse query string, but I don't think it is the most elegant solution.
Anybody has some experience to share?
Try this way.
public JsonResult ValidateMoney([Bind(Include = "Money")]BudgetValues budgetValues)
{
if(null != budgetValues)
{
decimal money = budgetValues.Money
}
return Json("I will always fail you.", JsonRequestBehavior.AllowGet);
}
Related
I am trying out with very basic MVC project using MVC 3.0 and Razor. Referring the turorial at this link.
I have created a strongly typed view for editing the Contacts using my model class called "Contact".
namespace Practice.Models
{
public class Contact
{
public string firstName;
public string lastName;
public string mobileNumber;
}
}
The "Index" method displays all the contacts using a list type view. When I click on "Edit" link against a contact, it displays the contact details in textboxes using an Edit View.
However, when I submit the Edit form, I am not getting the model values in controller action method. It shows null for each property. What exactly I may be missing here in such simple example?
DirectoryController
[HttpPost]
public ViewResult Edit(Contact model)
{
contactRepository.Update(model);
return View("Details", model);
}
View
#model Practice.Models.Contact
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm("Edit","Directory"))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
#Html.TextBoxFor(m => m.firstName)
#Html.TextBoxFor(m => m.lastName)
#Html.TextBoxFor(m => m.mobileNumber)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
You are missing { get; set; } on your model properties
I'm learning Jquery Mobile. I'm trying to set up the logon page for my .NET MVC3 site. My controller is just the standard MVC3 account controller.
Here is my Jquery Mobile page:
<html>
<head>
<title>Mobile Logon</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$(document).bind("mobileinit", function(){
$.extend( $.mobile , {
ajaxEnabled: false
});
});
</script>
<script src="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.js"></script>
</head>
<body>
<div data-role="page" data-theme="e">
<div data-role="header">
<a href="#Url.Action("Index", "Home")" data-icon="arrow-l" rel="external" >Back</a>
<h1>Logon</h1>
</div>
<div data-role = "content">
#Html.ValidationSummary(true, "Login was unsuccessful.")
#using (Html.BeginForm("Logon", "Account", FormMethod.Post, null))
{
<label for="Username">User Name (e-mail address)</label><input type="email" name="Username" />
<label for="Password">Password</label><input type="password" name="Password" />
<label><input type="checkbox" name="RememberMe" data-theme="c" />Remember Me</label>
<button type="submit" value="Log On"></button>
}
<center>or</center>
#using(Html.BeginForm("Register", "Account", FormMethod.Get, null ))
{
<button type="submit" value="Register for an account" data-transition="flip"></button>
}
</div>
</div>
When I test the page, if I leave the "Remember Me" box unchecked, then everything works fine. However, if I check the box and click "Log On", then the controller says that the model is invalid. As I step through the code, I notice that it also thinks that the value for "RememberMe" is false whether the box is checked or not.
Here is the view model for the logon page
public class LogOnModel
{
[Required]
[Display(Name = "E-mail address")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
You can use your extra mobile attributes when using the HtmlHelpers, an example is below:
#Html.TextBoxFor(x => x.UserName, new { type = "email" })
#Html.CheckBoxFor(x => x.RememberMe, new { data_theme = "c" })
MVC 3 converts underscores in attribute names to dashes, so your data-theme attribute remains in-tact. I have just tested this and it works perfectly for your needs.
I have a few different models with properties that I've decorated with data annotations for validation.
public class BillingModel
{
[Required,
DisplayName("First Name")]
public string FirstName { get; set; }
[Required,
DisplayName("Last Name")]
public string LastName { get; set; }
}
public class CustomerModel
{
[Required,
DisplayName("Address")]
public string Adress { get; set; }
[Required,
DisplayName("City")]
public string City { get; set; }
}
When I put them in a view model like this:
public class OrderViewModel
{
public BillingModel Billing { get; set; }
public CustomerModel Customer { get; set; }
}
They render out like this:
<input id="Business_FirstName" name="Business.FirstName" type="text" value="" />
<input id="Business_LastName" name="Business.LastName" type="text" value="" />
My Razor looks like this:
#Html.TextBoxFor(x => x.Business.FirstName)
#Html.TextBoxFor(x => x.Business.LastName)
I have many properties that need to live in their own classes as each class contains specific methods. Even if I put [Required] on each property in the View Model it still doesn't work.
You also need to put the following <script /> elements in your view (preferably the _layout.cshtml View if you will be using client side validation across all views):
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Modify the paths accordingly. But that should get your validation up and running.
Also, use the ValidationMessageFor() in your view. Like so:
#Html.TextBoxFor(x => x.Business.FirstName)
#Html.ValidationMessageFor(x => x.Business.FirstName)
#Html.TextBoxFor(x => x.Business.LastName)
#Html.ValidationMessageFor(x => x.Business.LastName)
Just for anyone else who comes across this, in addition to the other answer, you also need to have the following web.config settings enabled:
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
This is what enables the data annotations to have an affect on the rendered html.
Once you put the required Data Annotation in You Field in the View Models, for example
And, if it doesn't work, Just write this in the section script in Your View page that you are using the ViewModel like this:
[![enter image description here][2]]
I hope that can Help You!
And don't forget to use the tag decorator below to the field
#Html.ValidationMessageFor(x => x.Model.Name)
here is the scripts :
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
I am trying to get client validation working in MVC3 using data annotations. I have looked at similar posts including this MVC3 Client side validation not working for the answer.
I'm using an EF data model. I created a partial class like this for my validations.
[MetadataType(typeof(Post_Validation))]
public partial class Post
{
}
public class Post_Validation
{
[Required(ErrorMessage = "Title is required")]
[StringLength(5, ErrorMessage = "Title may not be longer than 5 characters")]
public string Title { get; set; }
[Required(ErrorMessage = "Text is required")]
[DataType(DataType.MultilineText)]
public string Text { get; set; }
[Required(ErrorMessage = "Publish Date is required")]
[DataType(DataType.DateTime)]
public DateTime PublishDate { get; set; }
}
My cshtml page includes the following.
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Post</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Text)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Text)
#Html.ValidationMessageFor(model => model.Text)
</div>
}
Web Config:
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Layout:
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
So, the Multiline Text annotation works and creates a text area. But none of the validations work client side. I don't know what i might be missing. Any ideas?? i can post more information if needed. Thanks!
1.)
Try adding the following into the view which you are validating
HtmlHelper.ClientValidationEnabled = true;
HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
I did not find it necessary to modify Web.config, so you may remove
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Good luck! Also, try putting in a known bad value to see if client side validation is triggered, the required annotation does not seem to be enough to display a message for a blank input.
2.)
Put below scripts in your view, it should work.
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Try to declare using public object :
public class Post_Validation
{
[Required(ErrorMessage = "Title is required")]
[StringLength(5, ErrorMessage = "Title may not be longer than 5 characters")]
public object Title { get; set; }
[Required(ErrorMessage = "Text is required")]
[DataType(DataType.MultilineText)]
public object Text { get; set; }
[Required(ErrorMessage = "Publish Date is required")]
[DataType(DataType.DateTime)]
public object PublishDate { get; set; }
}
I have a Create view which is passed a ViewModel. The ViewModel contains the following:
namespace MyProject.ViewModels
{
public class MyObjectCreateView
{
public MyObject MyObject { get; set; }
public List<OtherObject> OtherObjects { get; set; }
}
}
The objects are generated using Entity Framework. I have a metadata partial class for MyObject:
[MetadataType(typeof(MyObjectMetaData))]
public partial class MyObject
{
// Validation rules for the MyObject class
public class MyObjectMetaData
{
// Validation rules for MyObjectId
[DisplayName("MyObject")]
[Required(ErrorMessage = "Please enter the MyObject ID number.")]
[DisplayFormat( ApplyFormatInEditMode=true,
ConvertEmptyStringToNull=true,
HtmlEncode=true)]
[DataType(DataType.Text)]
[StringLength(25, ErrorMessage = "Must be under 25 characters.")]
public object MyObjectId { get; set; }
// Validation rules for Title
[Required(ErrorMessage = "Please enter the Title for MyObject.")]
[DataType(DataType.MultilineText)]
[StringLength(200, ErrorMessage = "Must be under 200 characters.")]
[DisplayFormat(ApplyFormatInEditMode = true,
ConvertEmptyStringToNull = true,
HtmlEncode = true)]
public object Title { get; set; }
Etc...
My Create view looks like this:
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<%:Html.ValidationSummary(true, "Please fix the following errors:") %>
<%:Html.EditorFor(model => model.MyObject) %>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
<div>
<%:Html.ActionLink("Back to List", "Index") %>
</div>
Finally, the editor for MyObject:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<TxRP.Models.MyObject>" %>
<%--EditorTemplate--%>
<fieldset>
<div class="editor-label"><%:Html.LabelFor(model => model.MyObjectId)%></div>
<div class="editor-field">
<%:Html.TextBoxFor(model => model.MyObjectId)%>
<%= Html.ValidationMessageFor(model => model.MyObjectId) %>
</div>
<div class="editor-label"><%:Html.LabelFor(model => model.Title)%></div>
<div class="editor-field">
<%:Html.TextAreaFor(model => model.Title, new { cols = "80" })%>
<%= Html.ValidationMessageFor(model => model.Title)%>
</div>
I have Client validation set, and all the scripts are in the master page:
<script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="../../Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
<script src="../../Scripts/MicrosoftMvcJQueryValidation.js" type="text/javascript"></script>
<script src="../../scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="../../Scripts/ui/minified/jquery.ui.core.min.js" type="text/javascript"></script>
<script src="../../Scripts/ui/minified/jquery.ui.datepicker.min.js" type="text/javascript"></script>
<link href="../../Content/Site.css" type="text/css" rel="Stylesheet" />
<link href="../../Content/jquery-ui/sunny/jquery-ui-1.8.4.custom.css" type="text/css" rel="Stylesheet" />
When I click the Save button, no validation happens. No client validation, no server validation (it doesn't even seem to hit the Post create action at all!); it just bombs on the entity framework model with a ConstraintException, because Title is null. Argh!
I'm sure it's just some silly thing I've overlooked, but I know I had it working at one point, and now it's not, and I've been trying to figure this out all week. Thanks for any help, I'm developing a callous on my forehead from banging it on my desk!
EDIT: Here is the controller:
public ActionResult Create(MyObject myObject)
{
if (!ModelState.IsValid)
{
//ModelState is invalid
return View(new MyObject());
}
try
{
//TODO: Save MyObject
return RedirectToAction("Index");
}
catch
{
//Invalid - redisplay with errors
return View(new MyObject());
}
}
and the exception stack trace:
at System.Data.Objects.DataClasses.StructuralObject.SetValidValue(String value, Boolean isNullable)
at MyProject.Models.MyObject.set_Title(String value) in C:\CodeProjects\MyProject\Models\MyProjectDB.Designer.cs:line 4941
Couple of remarks about your code:
You say that you have a view model but what I see looks more like an Entity Framework autogenerated model. Properties of type object, ... arghhh...
You include both MicrosoftMvcValidation.js and MicrosoftMvcJQueryValidation.js but those are mutually exclusive. You have to decide whether you will do client validation using MS Technology or jquery validate plugin.
You didn't show any code of the controller actions nor the exact exception stack trace you are getting. You are saying that the Post action is not hit but you get an exception. Where do you get this exception?