I have a Form where I successfully use unobtrusive-validation with the [remote] annotation.
I have other fields in the Form with [required] annotation in the model but I don't want client-side validation for these fields.
I only want server-side validation for [required] fields
I haven't found a solution and I wonder if it's easily feasible?
EDIT :
A part of my code
Part of my model :
I would like the first field : "Email" use Unobtrusive-validation and the second one : "PasswordHash" only use server-side validation even if it has [required] annotation.
Finally, i don't want an AJAX error message for all my form 's fields.
[Required(ErrorMessageResourceType = typeof(Project.Resources.Models.Accounts.User), ErrorMessageResourceName = "EMAIL_REQUIRED")]
[Display(Name = "EMAIL_DISPLAY", ResourceType = typeof(Project.Resources.Models.Accounts.User))]
[Remote("EmailExists", "User", "An account with this email address already exists.")]
public string Email { get; set; }
[Required(ErrorMessageResourceType = typeof(Project.Resources.Models.Accounts.User), ErrorMessageResourceName = "PASSWORDHASH_REQUIRED")]
[DataType(DataType.Password)]
[Display(Name = "PASSWORDHASH_DISPLAY", ResourceType = typeof(Project.Resources.Models.Accounts.User))]
public string PasswordHash { get; set; }
Part of the action in Controller
Server-side validation :
[HttpPost]
public ActionResult Register(User user)
{
if (ModelState.IsValid )
{
DataContext.User.Add(user);
DataContext.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
Ajax validation :
public JsonResult EmailExists(string email)
{
User user = DataContext.User.SingleOrDefault(x => x.Email == email);
return user == null ?
Json(true, JsonRequestBehavior.AllowGet) :
Json(
string.Format("an account for address {0} already exists.",
email), JsonRequestBehavior.AllowGet);
}
Part of the view :
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<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>
<div class="editor-label">
#Html.LabelFor(model => model.PasswordHash)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PasswordHash)
#Html.ValidationMessageFor(model => model.PasswordHash)
</div>
<p>
<input type="submit" name="op" id="edit-submit" value="#Project.Resources.Views.User.Register.SUBMIT_FORM" class="form-submit art-button" />
</p>
}
When I click on the sumbit button i would like a server-side validation.
And for some specific fields like Email i would like an Ajax Validation.
there might be better ways, but one way to accomplish this is to do the following
#using (Html.BeginForm("Register", "Home", FormMethod.Post, new { id = "registerForm" }))
{
#Html.ValidationSummary(true)
<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>
<div class="editor-label">
#Html.LabelFor(model => model.PasswordHash)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PasswordHash)
#Html.ValidationMessageFor(model => model.PasswordHash)
</div>
<p>
<input type="submit" name="op" id="edit-submit" value="#Project.Resources.Views.User.Register.SUBMIT_FORM" class="form-submit art-button" />
</p>
}
<script type="text/javascript">
// add the rules for the fields that you want client-side validation on
// leave out the fields that you dont want client-side validation. they will be validated
// on server side.
$("#registerForm").validate({
rules: {
Email: { required: true }
},
messages: {
Email: { required : "Email is required" }
}
});
</script>
Related
I have a model like:
public class Person
{
public int ID { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string FirstMidName { get; set; }
}
And the view:
#model ContosoUniversity.Models.Student
#using (Html.BeginForm("Edit", "Student", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.HiddenFor(model => model.ID)
<div
#Html.LabelFor(model => model.LastName, new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div >
#Html.LabelFor(model => model.FirstMidName, new { #class = "control-label col-md-2" })
#Html.EditorFor(model => model.FirstMidName)
#Html.ValidationMessageFor(model => model.FirstMidName)
</div>
<div>
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
The problem is that when I am rendering the view using Ajax Get using return PartialView("Edit", student); statement, the unobtrusive jQuery validation fails. The validation is working fine when I remove the hidden field #Html.HiddenFor(model => model.ID).
I have used below code to render the view using Ajax Get request:
function ShowEditPartialView(sender) {
$.ajax({
type: "GET",
url: "/Student/EditPartial",
data: {
id: courseid
},
async: false,
success: function (data) {
$("#EditCoursePartial").html(data);
///because the page is loaded with ajax, the validation rules are lost, we have to rebind them:
$('form').removeData('validator');
$('form').removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse('form');
}
});
}
Any idea on how it will be resolved.
I'm currently working on my first MVC3 application at work (using the Razor view engine), and decided to use the open source Telerik Q1 2012 controls since they will provide a lot of the functionality I need (and look nice as well). Right now the issue I'm having is using the Telerik Editor control and binding to my view model. I have standard Html.EditorFor() controls on the page that return the value in the ViewModel correctly, but the property bound to Telerik Editor is null. Their documentation is completely useless (it only mentions EditorFor one time), and it doesn't seem like they answer too many questions on the forum either. My main question is, how do I bind the Telerik MVC3 Editor to a model and have it set the property that's bound to it? My code for the view model is below (thanks for any help you can provide, and keep in mind, I'm brand new to MVC, I'm doing this project on my own to get familiar with it and introduce some new technologies to the group):
public class SupportViewModel
{
[Display(Name = "Ticket Subject")]
[MaxLength(30)]
[Required(ErrorMessage = "The ticket subject is required.")]
public string TicketSubject { get; set; }
[Display(Name = "Support Issue")]
[Min(1, ErrorMessage = "You must select a support issue.")]
public int SupportIssueID { get; set; }
[Display(Name = "Ticket Priority")]
[Min(1, ErrorMessage = "You must select a ticket priority.")]
public int TicketPriorityID { get; set; }
//public string EmployeeID { get; set; }
public bool IsClosed { get; set; }
[Required(ErrorMessage = "The detail message is required.")]
public string DetailMessage { get; set; }
}
View Code:
#model RadixMVC.ViewModels.SupportViewModel
#{
ViewBag.Title = "Create New Support Ticket";
}
<h2>Radix Support: Create New Support Ticket</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 style="width: 500px">
<legend>Create New Support Ticket</legend>
<div class="editor-label">
#Html.LabelFor(model => model.TicketSubject)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TicketSubject)
#Html.ValidationMessageFor(model => model.TicketSubject)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SupportIssueID)
</div>
<div class="editor-field">
#Html.DropDownList("SupportIssueID", string.Empty)
#Html.ValidationMessageFor(model => model.SupportIssueID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TicketPriorityID)
</div>
<div class="editor-field">
#Html.DropDownList("TicketPriorityID", string.Empty)
#Html.ValidationMessageFor(model => model.TicketPriorityID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IsClosed)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.IsClosed)
#Html.ValidationMessageFor(model => model.IsClosed)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DetailMessage)
</div>
<div class="editor-field">
#*#Html.EditorFor(model => model.DetailMessage)*#
#Html.ValidationMessageFor(model => model.DetailMessage)
<br />
#{ Html.Telerik().EditorFor(model => model.DetailMessage)
.Name("DetailMessageEditor")
.HtmlAttributes(new { style = "height: 200px" })
.Encode(false)
.Render();
}
</div>
<div>
<br />
<input type="submit" value="Create Ticket" title="Submits a new support ticket" />
<input type="submit" onclick="parent.location='#Url.Action("Index", "Support", "Index")'" value="Cancel" title="Return to Support Home" />
</div>
</fieldset>
}
And finally, Controller Code:
[HttpPost]
public ActionResult Create(SupportViewModel vm)
{
if (ModelState.IsValid)
{
SupportTicket SupportTicket = new SupportTicket()
{
SupportTicketID = Guid.NewGuid(),
EmployeeID = "123456",
TicketOpenDate = DateTime.Now,
TicketModifiedDate = DateTime.Now,
IsClosed = vm.IsClosed,
TicketSubject = vm.TicketSubject,
SupportIssueID = vm.SupportIssueID,
TicketPriorityID = vm.TicketPriorityID
};
TicketDetail TicketDetail = new TicketDetail()
{
TicketDetailID = Guid.NewGuid(),
SupportTicketID = SupportTicket.SupportTicketID,
TicketOrder = 1,
EmployeeID = "123456",
DetailDate = DateTime.Now,
DetailMessage = vm.DetailMessage
};
SupportTicket.TicketDetails.Add(TicketDetail);
db.SupportTickets.Add(SupportTicket);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.SupportIssueID = new SelectList(db.SupportIssues, "SupportIssueID", "Name", vm.SupportIssueID);
ViewBag.TicketPriorityID = new SelectList(db.TicketPriorities, "TicketPriorityID", "Name", vm.TicketPriorityID);
return View(vm);
}
I was able to get this working. The documentation is either very outdated or just doesn't explain how to do this very well (probably both). But I was able to get this working by making the following change to my Razor syntax:
<div class="editor-label">
#Html.LabelFor(model => model.DetailMessage)
</div>
<div class="editor-field">
#*#Html.EditorFor(model => model.DetailMessage)*#
#Html.ValidationMessageFor(model => model.DetailMessage)
<br />
#{ Html.Telerik().EditorFor(model => model.DetailMessage)
//.Name("DetailMessageEditor")
.HtmlAttributes(new { style = "height: 200px" })
.Encode(true)
.Render();
}
</div>
Removing the "Name" property from the control solved the problem of not getting anything back, but when I tried to save, I immediately got an error (something to do with XSS, cross-site scripting), and I assumed it was because the HTML wasn't being encoded. I changed the Encode property to true, and now all is good.
Came across a similar thing today.
I was using a View Model and the property I wanted to bind to was was a property of a child object in the View Model.
When I submitted, the value in the RTE was not being bound. When I looked in Request.From object I could see the the value was being returned in the correct format for it to bound in the usual way so I was a little confused.
Anyway, if you want it to bind you need to give the exact name of your property to the the RTE so in your case
.Name("DetailMessage")
should work but
.Name("DetailMessageEditor")
will not.
Im my case i had to name the RTE
.Name("object.Property")
where object is the child object on the View model where my property lives to get it to work
Hope this helps someone.
I have a problem trying to edit. I work with Areas for better management the application.The problem is in the areas called "Administrator".
Next is the controller code (OfficeControlle), I use a session variable has been previously created and functions to edit the model data I get.
public ActionResult Edit()
{
decimal id;
id = (decimal)Session["consul"];
CAMPUS_UNIVERSITY campus_university = db. CAMPUS_UNIVERSITY.Single(s => s.Idoffice == id);
ViewData.Model = db.OFFICE.Single(c => c.Idoffice == id);
ViewBag.University = db.UNIVERSITY.Single(u => u.IdUniversity == campus_university.IdUniversity);
ViewBag.campus = db.CITY_CAMPUS.Single(u => u.IdCity == campus_university.Idcitycampus);
return View(sede_universidad);
}
[HttpPost]
public ActionResult Edit(CAMPUS_UNIVERSITY campus_university, OFFICE office)
{
if (ModelState.IsValid)
{
db.CAMPUS_UNIVERSITY.Attach(campus_university);
db.ObjectStateManager.ChangeObjectState(campus_university, EntityState.Modified);
db.SaveChanges();
db. OFFICE.Attach(office);
db.ObjectStateManager.ChangeObjectState(office, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.IdCitycampus = new SelectList(db.CITY_CAMPUS, "IdCity", "Name", campus_university.IdCitycampus);
ViewBag.IdConsultorio = new SelectList(db.OFFICE, "Idoffice", "addressoffice", campus_university.Idoffice);
ViewBag.IdUniversidad = new SelectList(db.UNIVERSITY, "IdUniversity", "Name", campus_university.IdUniversity);
return View(campus_university);
}
Next is the view code
#model RolMVC3.Models.CAMPUS_UNIVERSITY
#{
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()) {
#Html.ValidationSummary(true)
<h2> #ViewBag.University.Name - #ViewBag.Campus.Name </h2>
<fieldset>
<legend>OFFICE</legend>
#Html.HiddenFor(model => model.IdUniversity)
#Html.HiddenFor(model => model.IdCitycampus)
#Html.HiddenFor(model => model.Idoffice)
<div class="editor-label">
#Html.LabelFor(model => model.addresscampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.addresscampus)
#Html.ValidationMessageFor(model => model.addresscampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.phonecampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.phonecampus)
#Html.ValidationMessageFor(model => model.phonecampus)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.emailcampus)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.emailcampus)
#Html.ValidationMessageFor(model => model.emailcampus)
</div>
<fieldset>
<legend>OTHER DATE</legend>
#Html.Partial("_office", Model.OFFICE)
</fieldset>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("back", "Index")
</div>
The problem appears when I press the "Save" button, get the following error:
The parameters dictionary contains a null entry for parameter 'Id' of non-nullable type ''System.Decimal' ' for method ''System.Web.Mvc.ActionResult Index(System.Decimal)' in ''RolMVC3.Areas.Administrator.Controllers.OfficeController''
When you are redirecting here:
return RedirectToAction("Index");
make sure that you pass the id in the query string as it looks like your Index action requires it as parameter:
return RedirectToAction("Index", new { id = campus_university.IdUniversity });
I'm assuming that your Index action method looks something like this (please correct me if I am wrong):
public ActionResult Index(decimal id)
{
// Your method's code
}
So where you do return RedirectToAction("Index"); you are trying to redirect to an action method that takes no parameters. But in this case there is an action method that requires a parameter, namely id. So when redirecting you need to change your code and supply this id parameter.
This is what you could do:
return RedirectToAction("Index", new { id = /* put your id here */ });
I have created a custom validator in my asp.net mvc3 application like this:
{
if (customerToValidate.FirstName == customerToValidate.LastName)
return new ValidationResult("First Name and Last Name can not be same.");
return ValidationResult.Success;
}
public static ValidationResult ValidateFirstName(string firstName, ValidationContext context)
{
if (firstName == "Nadeem")
{
return new ValidationResult("First Name can not be Nadeem", new List<string> { "FirstName" });
}
return ValidationResult.Success;
}
and I have decorated my model like this:
[CustomValidation(typeof(CustomerValidator), "ValidateCustomer")]
public class Customer
{
public int Id { get; set; }
[CustomValidation(typeof(CustomerValidator), "ValidateFirstName")]
public string FirstName { get; set; }
public string LastName { get; set; }
}
my view is like this:
#model CustomvalidatorSample.Models.Customer
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#using (#Html.BeginForm())
{
#Html.ValidationSummary(false)
<div class="editor-label">
#Html.LabelFor(model => model.FirstName, "First Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName, "Last Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
</div>
<div>
<input type="submit" value="Validate" />
</div>
}
But validation doesn't fire. Please suggest solution.
Thanks
How do you know the validation doesn't fire? Are you setting a break point in your controller?
You are not displaying any validation errors in your view. You need to add the following lines to the view.
#Html.ValidationMessageFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.LastName)
You will want to remove the custom validation from the class. Leave it on the properties though.
I have a problem with the following code. Basically when I call updatemodel it fails but I dont get an inner exception. If i change the drop down to a text box it works.
class:
public class Member
{
[Key]
public int MemberID { get; set; }
[StringLength(50),Required()]
public string Name { get; set; }
[Range(0,120)]
public short Age { get; set; }
[Required(),MaxLength(1)]
public string Gender {get; set;}
[Required()]
public virtual Team Team { get; set; }
}
controller methods:
[HttpGet]
public ActionResult ViewMember(int id)
{
try
{
var m = db.GetMember(id);
var maleItem = new SelectListItem{Text = "Male", Value= "M", Selected=m.Gender == "M"};
var femaleItem = new SelectListItem{Text = "Female", Value="F", Selected=m.Gender == "F"};
List<SelectListItem> items = new List<SelectListItem>();
items.Add(maleItem);
items.Add(femaleItem);
var genders = new SelectList(items, "Value", "Text");
ViewBag.Genders = genders;
return View(m);
}
catch (Exception ex)
{
return View();
}
}
[HttpPost]
public ActionResult ViewMember(Member m)
{
try
{
var member = db.GetMember(m.MemberID);
m.Team = db.GetTeam(member.Team.TeamID);
UpdateModel(member);
db.Save();
return RedirectToAction("ViewMembers", new { id = member.Team.TeamID });
}
catch (Exception ex)
{
return View();
}
}
and finally cshtml code:
#model GreenpowerAdmin.Models.Member
#using GreenpowerAdmin.Helpers
#{
ViewBag.Title = "ViewMember";
}
<h2>ViewMember</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>Member</legend>
#Html.HiddenFor(model => model.MemberID)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Team.Name)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.Team.Name)
#Html.ValidationMessageFor(model => model.Team.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Gender)
</div>
<div class="editor-field">
#Html.DropDownList("Gender", ViewBag.Genders as SelectList)
#Html.ValidationMessageFor(model => model.Gender)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "ViewMembers", new { id=Model.Team.TeamID })
</div>
When I click the save button the updatemodel line fails. As said above, it doesn't fail if I use a text box for gender. Does anyone know what is making it fail or how to debug it?
Try declaring the MemberID property as a nullable integer:
[Key]
public int? MemberID { get; set; }