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>
Related
Using the create page I am trying to update two tables using razor page. I create another class where I populated all the properties of both tables to make a joinder. Now my form is not sending data to my defined method, where am i making the mistake?
#page
#model Restaurant.Model.CityBranchJoinder
#{
ViewData["Title"] = "Create";
}
<hr />
<div class="row">
<div class="col-md-4">
#using (Html.BeginForm("SaveRecord","Cities/Create",FormMethod.Post))
{
<h1> Brand ID</h1>
#Html.TextBoxFor(model=>model.BranchID)
<h1> Brand Name</h1>
#Html.TextBoxFor(model=>model.BranchName)
<h1> CityID</h1>
#Html.TextBoxFor(model=>model.CityId)
<h1> CityName</h1>
#Html.TextBoxFor(model=>model.CityName)
<input type="submit" value="Create" class="btn btn-primary" />
}
</div>
</div>
[BindProperty]
public City City { get; set; }
public Branch Branch { get; set; }
public CityBranchJoinder CityBranchJoinder { get; set; }
[HttpPost]
public IActionResult SaveRecord(CityBranchJoinder model)
{
City city= new City();
Branch branch= new Branch();
city.CityId= model.CityId;
city.CityName= model.CityName;
_context.City.Add(city);
_context.SaveChangesAsync();
branch.BranchID= model.BranchID;
branch.BranchName= model.BranchName;
branch.CityId= model.CityId;
_context.Branch.Add(branch);
_context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
I tried changing Cities/Create to Create only but it does not work. Create is my Page Model name but on top I am using another model so that I could post to two tables using one form. But my form does not submit data to my action item.
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 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);
}
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?