I have a form in cfwheels. I am using model which automatically detect if the field is empty.
View:
#startFormTag(action="t_validate")#
<div>
#textField(label="Supervisor Name:", objectName="supervisor", property="name")#
#errorMessageOn(objectName="supervisor", property="name")#
</div>
<div>
#textField(label="Inspector Name:", objectName="inspector", property="name")#
#errorMessageOn(objectName="inspector", property="name")#
</div>
#submitTag()#
#endFormTag()#
Controller Action:
public function t_validate()
{
title = "Complete";
supervisor = model("supervisors").new();
inspector = model("inspectors").new();
if(isPost() and StructKeyExists(params, "inspector"))
{
supervisor = model("tb_mchn_supervisors").new(params.supervisor);
supervisor.save();
inspector = model("tb_mchn_inspectors").new(params.inspector);
inspector.save();
}
}
So Supervisor has a column named "NAME" and inspector has a column named "NAME". Is there a way to modify the default column error messages. Right now, it show as "NAME can't be empty" for both fields. Perhaps something like "supervisor name is empty or inspector name is empty" would be better.
You can define custom Validation Messages in the model files with for example
validatesPresenceOf() and the message Parameter.
http://docs.cfwheels.org/v1.4/docs/validatespresenceof
Related
I have a form that has several controls in it. I added data annotation to display an error message to the user when the required field are left empty. The TextBoxes and other controls display the message, which is an "*" before the label name, but the dropdownlist does not not. Once the user get rid of all the error messages and click on submit again, then, the message for the dropdown box is display. How do I force the dropdown box to display the message at the same time with the textbox?
Additional information:
Here is a sample of my data annotation:
[MetadataType(typeof(UserMetaData))]
public partial class UserMeta
{
}
public class UserMetaData
{
[Required(ErrorMessage = "*")]
public int GenderID { get; set; }
//The gender ID is displayed in a dropdown
list with "Select" as the default option. Then, it has all the other genders
showing in the dropdown once it is clicked on.
[Required(ErrorMessage = "*")]
public DateTime DataOfBirth{ get; set; }
}
In my view, I am using
#Html.ValidationMessageFor(model => model.DataOfBirth) //This is working fine.
#Html.ValidationMessageFor(model => model.GenderID)
//Here is the dropdown
#Html.DropDownList("GenderID", null, "Select", new { style = "width:200px;", onchange = "ValidateDropdown()" })
//This is the one that is not working as expected. I could get it to work using javascript, but I am trying not to it if I there is a way to get it to work properly using data annotation.
Thank in advance for your help.
I could not get it to work properly on the server side. As a result, I had to write a JQuery function that does the validation for the dropdown on the client side. Then, I do the post only if there is a selection on the dropdown.
What I want to do is automatically add an image span after my input textboxes if the [Required] attribute decorates my ViewModel property be it an integer, double, string, date etc
For example, my ViewModel might look like
public class MyViewModel
{
[Required]
public string Name { get; set; }
}
and my View would look like
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
and the output would be something like
<input id="Name" class="text-box single-line" type="text" value="" name="Name" data-val-required="The Name field is required." data-val-length-max="20" data-val-length="The field Name must be a string with a maximum length of 20." data-val="true">
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="Name"></span>
-- Note the automatically added span
<span class="indicator required" style="width: 11px;"></span>
I was intending to have some css that would show the image i.e.
span.required {
background-image: url("required.png");
}
Is this possible to do or do I need to create my own Helper method to implement this type of functionality?
Yes, it's possible, but in general I wouldn't recommend it, because templates are really there to customize type rendering, and you should be able to create templates without worrying if it overrides another template.
I would instead create a custom LabelFor helper, such as the one described here:
http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx
or here:
http://weblogs.asp.net/raduenuca/archive/2011/02/17/asp-net-mvc-display-visual-hints-for-the-required-fields-in-your-model.aspx
A third option is to not do anything in MVC, but rather add some javascript that will add the indicator based on the standard MVC validation data attributes (if you're using unobtrusive validation). See the answer here:
https://stackoverflow.com/a/8524547/61164
What I did was to modify the jquery.validate.unobtrusive JS file to add a second container, specifically for your images, if there is a validation error.
var container2 = $(this).find("[data-valimg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = $.parseJSON(container.attr("data-valimg-replace")) !== false;
container2.removeClass("img-validation-valid").addClass("img-validation-error");
Then don't forget to bind it to the model:
error.data("unobtrusiveContainer", container2);
Finally, empty it in the if (replace) code block:
if (replace) {
container.empty();
container2.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
On success, remember to hide it:
var container2 = error.data("unobtrusiveContainer"),
replace = $.parseJSON(container.attr("data-valimg-replace"));
if (container2) {
container2.addClass("img-validation-valid").removeClass("img-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container2.empty();
}
}
If you take a look at the onError and onSuccess functions in the file, you should be able to find out where you can put them in.
In your view, add the following line of code to each form input there's validation for:
<img class="img-validation-valid" data-valimg-replace="true" data-valimg-for="<replace with field name here, ie. Name>" src="required.png" />
I've only tested this with the [Required] attribute, but it works. I'm also pretty sure you can use this for generating other stuff as well, not just images.
I am using FOSUserBundle in my Symfony2 project. I added 'birthday' field in User entity, because it is required in registration form. I also added a proper field (type=birthday) to the registration form. I have to check if age of a user is above 18. I prepared my own Constraint for this following this tutorial. Everything works perfectly, but error message is attached to form not to field, and I want error message next to field. Instead I get it above the whole form. Every other error in form is displayed next to a proper field. Does anybody know how to force constraint to be attached to the field, not to the form?
EDIT:
Twig code fragment which renders this particular field:
<div class="grid_8" style="margin-bottom:20px;">
<div class="grid_2 alpha">{{ form_label(form.date_of_birth)}}</div>
<div class="grid_4">{{ form_widget(form.date_of_birth)}}</div>
<div class="grid_2 omega">{{ form_errors(form.date_of_birth)}}</div>
</div>
At the begining of the form I also have:
<div class="grid_8">
{{form_errors(form)}}
</div>
If you attach callback to form – not to particular field, you should set property path a bit different way:
public function isFormValid($data, ExecutionContext $context)
{
if ( $condition == false ) {
$context->addViolationAt('[date_of_birth].date_of_birth', 'You are too young!');
}
}
You can add the violation to one particular field with addViolationAtSubPath() instead of the classic addViolation() used in the validator. You can have a look at the method definition here.
An example
Lets take the example of a validator that need to validate that the username property is alphanumeric:
class ContainsAlphanumericValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!preg_match('/^[a-zA-Za0-9]+$/', $value, $matches)) {
$this->context->addViolationAtSubPath('username',$constraint->message, array('%string%' => $value));
}
}
}
Edit
You can also take a look at addViolationAtPath() and addViolationAt().
I am using ModelState.AddModelError to display error message to user when Model do not pass validation. What is the best method do display information message when validation is passed. I do not want to add additional HTML elements. Can I use ModelState object to send information messages?
You could test if the model is valid and display a corresponding message
#if (ViewData.ModelState.IsValid)
{
<div>Your model is valid</div>
}
Obviously if you don't want this to be displayed all the time even when you first arrive at the page you could use an additional view model boolean property to indicate whether you want to display the message or not. Then inside your POST action set its value to true when everything passes validation and in the view:
#if (Model.ShouldShowSuccess && ViewData.ModelState.IsValid)
{
<div>Your model is valid</div>
}
I built a PartialView to display success posts.
It's near the Html.ValidationSummary().
When a ModelState is valid I value a TempData variable with the IsValid message, so in my View I have this:
#Html.ValidationSummary()
#if (ViewData.ModelState.IsValid && TempData["ModelIsValidMsg"] != null)
{
#Html.Partial("PostSuccess", TempData["ModelIsValidMsg"])
}
In my Controller:
if (ModelState.IsValid)
{
TempData["ModelIsValidMsg"] = "Your success msg";
}
else
{
ModelState.AddModelError("Your error msg");
}
Inside the PartialView I display the TempData message.
We have a ASP.NET MVC 3 application that uses unobtrusive jQuery validation. The page allows to add children objects to the model in the same go. The <form> contains a grid for the children, and some input fields for adding new children.
Simplified example with Issue as the Model and Subtasks as the children:
Issue.cshtml -> Defines the form and includes fields for the issue as well as its subtasks.
#model Issue
#using (Html.BeginForm("Create", "Issues", FormMethod.Post, new { id = "mainForm" })
{
#Html.TextBoxFor(model => model.Summary)
#Html.Partial("SubtaskFields", new Subtask())
#Html.Partial("SubtasksGrid", model.Subtasks)
}
SubtaskFields.cshtml:
#model Subtask
#Html.TextBoxFor(model => model.Summary)
<button id="add">Add</button>
SubtasksGrid.cshtml:
#model IEnumerable<Subtask>
<table>
#foreach (var subtask in Model)
{
<tr>
<td>
#subtask.Name
<input type="hidden" name="Subtasks[#subtask.Index].Name" value="#subtask.Name"/>
</td>
</tr>
}
</table>
The point is, when submitting the form, only the properties of the issue (Issue.Name, e.g.), plus the hidden fields for the children (Subtask.Name, e.g.) should be validated and submitted.
We have some javascript code that hooks on the "add" button, and adds a new subtask based on the values in the SubtaskFields.cshtml partial view. That script validates the input fields first. In order for this to work, we use the TextBoxFor etc. html helpers for the SubtaskFields.cshtml, too, rendering a dummy/default Subtask object (new Subtask()). Our javascript the uses $("#mainForm").validate().element(...) to validate the SubtaskFields before adding a new subtask.
The big problem with this approach is that the jQuery unobtrusive validation framework automatically hooks on the submit button and validates all fields within the form before submitting the form. I.e., even the subtask fields are validated. This does not make any sense. Say that the subtask name is mandatory (which means the user can only click on "add" if he has filled in a subtask name). But if the user does not click on "add", the values in the Subtask Fields don't have any meaning and can in particular be left blank. In this case, in our current setting, jQuery validation fails because a mandatory field was left blank.
How can this be solved?
This is what we've come up with:
Add an attribute to all subtask fields (which should not be validated when submitting the form), e.g. "data-val-ignore".
Set the ignore setting on the form's validator to "[data-val-ignore]"
For the add button, in order to validate the subtask fields (which are normally ignored), iterate over them, and for each field, remove the attribute, re-parse to genereate the rules, execute validation, add the attribute, parse one more time.
Ad 2:
$(document).ready(function () {
$.data($('form')[0], 'validator').settings.ignore = "[data-val-ignore]";
});
Ad 3:
$(allSubtaskFields).each(function() {
$(this).removeAttr("data-val-ignore");
$.validator.unobtrusive.parseElement(this, false);
if (!$("mainForm").validate().element($(this))) { result = false; }
$(this).attr("data-val-ignore", "true");
$.validator.unobtrusive.parseElement(this, false);
});
I would suggest moving #Html.Partial("SubtasksGrid", model.Subtasks) outside of your form, and either having it in a single separate form, or have the partial generate a form for each grid row.
This will address your validation problems with your main form, and should also permit you to simplify validation of each row in SubTasksGrid.
To validate part of the form, wrap the section or the controls you want to validate into a div with an #id or .class and do the following:
var validator = $("#myForm").validate();
var isValid = true;
$("myDivToBeValidated").find("*[data-val]").each(function (indx, elem) {
if (!validator.element(elem)) {
isValid = false;
}
});
//this part of form is valid however there might be some other invalid parts
if (isValid)
//do your action, like go to next step in a wizard or any other action
goToNextStep();
I hope it is clear, if not please leave a comment. For more info about jQuery validation plugin and element() function, check this
Looks like you are working against the MVC egine here.
I would use Editor templates and Display templates, EditorFor template for the stuff you wanna validate and post, and Display template for the stuff you dont wanna post and validate.. If you have a TextBoxFor in the display template make sure its binding property has no Required attribute, and if its a value type make it nullable.