Reputation: 5356
Using ASP.NET MVC3, Razor and jQuery Unobtrusive validation (as provided out of the box by Microsoft).
How can you mark fields as required 'on the fly', i.e. only in certain circumstances? For example, if user is in the role 'publisher', there is a 'Publish Date' and 'Publish' button. The 'Publish Date' field is required when the 'Publish' button is pressed, but not when the 'Save Draft' button is. If the user is not in that role, then the 'Publish' button is not shown in the form and therefore not required.
I'm sure this is not something that can be done out of the box and extra code is required both client side (jQuery Validate) and server side. If it can, it is not obvious how it can be done.
Upvotes: 5
Views: 1378
Reputation: 969
I'll explain the idea in a short example. We have the checkbox 'IsMasterProject' to set required for the 'MasterProjectNo' field:
To do the required 'on the fly' you need the following things:
Define your model with the field, that is not strict [Required]
class ProjectList {
public bool IsMasterProject { get; set; }
// this field will be optionally required,
// we do not need the [Required] attribute
public string MasterProjectNo { get; set; }
}
Create a view with the example field code:
<div class="data-field">
<div class="editor-label">
<div id="IsMasterProjectLabel">
Is Master Project
</div>
</div>
<div class="editor-field">
<input id="IsMasterProject" class="check-box" type="checkbox" value="true" name="IsMasterProject" data-val-required="The IsMasterProject field is required." data-val="true" checked="checked">
</div>
</div>
<div class="data-field">
<div class="editor-label">
<div id="MasterProjectNoLabel">
Master Project No
</div>
</div>
<div class="editor-field">
<input id="MasterProjectNo" type="text" value="" title="" style="width: 9.2em" placeholder="" name="MasterProjectNo" maxlength="15" data-val-length-max="15" data-val-length="The field MasterProjectNo must be a string with a maximum length of 15." data-val="true">
</div>
</div>
Add the Java Script to handle the click code and add or remove 'required' mark:
$(function () {
$("#IsMasterProject").change(function () { OnIsMasterProjectValueChange(); });
OnIsMasterProjectValueChange();
});
function OnIsMasterProjectValueChange() {
if ($('#IsMasterProject').is(':checked')) {
$('#IsMasterProjectLabel').append('<span class="label-required">*</span>');
}
else {
$('#IsMasterProjectLabel span').remove()
}
};
In the controller you can prepare the show action:
[Authorize]
public ActionResult Edit(int id)
{
try
{
ProjectList project = prepare_ProjectList(id);
return View(project);
}
catch (Exception ex)
{
sysHelper.LogError(ex, ModelState); ModelState.AddModelErrorException(ex, Request, "Probably selected data doesn't exist."); return View("Error");
}
}
In the save action you can verify the conditions you required:
[HttpPost]
public ActionResult Edit(ProjectList project)
{
try
{
if (ModelState.IsValid)
{
/* ------------------------------------------------------------------------ */
/* HERE YOU CAN ADD YOUR CODE TO CHECK THE FIELD */
/* ------------------------------------------------------------------------ */
if (project.IsMasterProject && string.IsNullOrEmpty(project.MasterProjectNo))
{
ModelState.AddModelError("Model", "The MasterProjectNo field is required.");
}
/* ------------------------------------------------------------------------ */
else
{
project.UserID = CurrentUser.ID;
project.C_updated = DateTime.Now;
db.ProjectList.Attach(project);
db.Entry<ProjectList>(project).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
catch (Exception ex)
{
sysHelper.LogError(ex, ModelState);
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
prepareViewBag(project);
return View(project);
}
This works like a charm :) Good luck.
Upvotes: 0
Reputation: 9051
If you were doing this in webform-land you would instantiate a RequiredFieldValidator in the button's click event handler and apply it to the field that should become required.
In mvc-land this isn't obvious. This SO question/answer demonstrates how to handle a button click - you may be able to extend it to instantiate a RequiredFieldValidator and apply it to the field.
In jquery you can add something like:
$("#buttonid").on("click", function() { $("#fieldToBeRequiredId").rules("add", {
required: true }); }
Upvotes: 1
Reputation: 37523
This sounds like it is less model specific and more view specific. Even if you could dynamically bind a requirement of this nature to the model, it would go against the purpose of MVC in separating model logic from view logic. I would recommend that you create a template for the publishing controls that is included (along with supporting validation) when you have a model that holds the role of "Publisher".
Upvotes: 0