ASP.NET MVC Unobtrusive validation - why form context is needed? - asp.net-mvc

I'm trying to enable unobtrusive javascript validation for dynamically created items. The problem with javascript was already solved in another SO question and this is not the case here.
Dynamic creation of items in this case is just cloning of one empty item that is generated outside of the main form.
The problem is that if I use html helpers like TextBoxFor, CheckBoxFor, ... outside the html form element then attributes required in order for the validation to work (eg. data-val-required) are not generated.
I've already checked the MVC source code and there is a line that returns empty attribute list if FormContext is null. (this throws no exceptions)
Why?

You could manually fake a form context. For example if you had some partial view which doesn't contain a <form> element and which is called using AJAX to regenerate some input elements you could do this:
#model MyViewModel
#{
ViewContext.FormContext = new FormContext();
}
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
#Html.ValidationMessageFor(x => x.Foo)
The corresponding input elements will now posses the data-* attributes. But that might not be enough. If you are only refreshing (using AJAX) only a portion of the <form> but not actually replacing the form element in the DOM calling $.validator.unobtrusive.parse wouldn't suffice. You need to remove any previous validations associated to this element:
success: function(result) {
// we are replacing only a portion of the form
$('#somePartOfTheForm').html(result);
$('form').removeData('validator');
$('form').removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse('form');
}

Related

What us the purpose of the Editable attribute if not to control editing on a field?

Nearly all my properties in my view model are decorated with [Editable(false)]', but when I scaffold a view, that usesEditorFor` these properties, they are all still editable on the form.
Must I now manually change all EditorFor to DisplayFor to prevet editing? OK, I will eventually change the T4 that generates the edit form, but really, what purpose does this attribute serve then?
EditorFor works with metadata, so if you want to add html attributes you could always do it. Another option is to simply write a custom template and use TextBoxFor:
<%= Html.TextBoxFor(model => model.Control.PeriodType,
new { disabled = "disabled", #readonly = "readonly" }) %>
Extracted from here:
Html attributes for EditorFor() in ASP.NET MVC

Detect if you are adding or updating within an EditorTemplate View

I have a View that I am using as an EditorTemplate. I want to limit what the user can edit vs. what they can insert. My EditorTemplate View is typed as SomeModel and I know that if SomeModel.Id is not 0, that means we are doing an edit, otherwise we are doing an insert. I thought I'd be able to do something like:
#if (Model.Id == 0)
{
//show "insert-specific" UI
}
but for some reason, I always get 0's, nulls, default, etc. when I check via Model. whereas the Html helper methods pick up the true value just fine, such as:
#Html.TextBoxFor(model => model.Id)
Again, the value of Model.Id is always 0, even when #Html.TextBoxFor(model => model.Id) shows another value.
Is there a better way to achieve what I am trying to do?
Note: Not sure that it matters, but I'm using the Telerik MVC Grid control. It doesn't seem to allow for a different View for inserting vs. editing.
Yo,
If you are using Ajax binding then the EditorTemplate is serialized and send to the client where it is re-populated with different values each time you edit a record or add new record.
If you are using ajax binding then you can use the OnEdit client event and check whether or not the e.mode is edit or insert. Then you can manipulate that editor with JavaScript.

ASP.NET MVC Validation add class to containing div

I'm using bootstrap CSS form styles, When a textbox gets a validation error message, I need to put the class "error" on the containg . How can I do this?
Problem is, all the validations fire on ajax before submitting the form, except for my custom validators which only fire on post. So need to make sure it happens 4 both scenarios.
http://twitter.github.com/bootstrap/base-css.html#forms
Inside the onError function in jquery.validate.unobtrusive, just add the .addClass("error") line like this:
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
container.parents(".field-encapsulator:first").addClass("error");
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
ASP.NET MVC adds the field-validation-error class to the error message element, and input-validation-error to form controls, both on the server-side and client-side via javascript. There's no containing element, depending on your code the form control and its label may or may not be under the same containing element. And, even if they do, MVC will set the mentioned classes to the form control and error message element and not the containing element.
Also, when you autogenerate a form using Html.EditorForModel() the generated markup is like this:
<div class="editor-label"><label for="foo">Foo</label></div>
<div class="editor-field"><input name="foo"/></div>
There's no containing element that could map to the control-group class on Twitter Bootstrap. You could change this template by adding an EditorTemplates/Object.cshtml template.
I'd suggest you adapt Twitter Bootstrap to ASP.NET MVC and not the other way around.
As described in some of the answers at How to add a 'submitHandler' function when using jQuery Unobtrusive Validation?, the settings can be accessed by $("form").data("validator").settings.
And you can then set any valid/invalid class you like:
var settings = $("form").data("validator").settings;
settings.errorClass += " is-invalid";
settings.validClass += " is-valid";

Differences between Html.TextboxFor and Html.EditorFor in MVC and Razor

Why by default were these changed when adding a new "edit" view? What are advantages when using EditorFor() vs. TextboxFor()?
I found this
By default, the Create and Edit scaffolds now use the Html.EditorFor helper instead of the Html.TextBoxFor helper. This improves support for metadata on the model in the form of
data annotation attributes when the Add View dialog box generates a view.
Quoted from here.
The advantages of EditorFor is that your code is not tied to an <input type="text". So if you decide to change something to the aspect of how your textboxes are rendered like wrapping them in a div you could simply write a custom editor template (~/Views/Shared/EditorTemplates/string.cshtml) and all your textboxes in your application will automatically benefit from this change whereas if you have hardcoded Html.TextBoxFor you will have to modify it everywhere. You could also use Data Annotations to control the way this is rendered.
TextBoxFor: It will render like text input html element corresponding to specified expression. In simple word it will always render like an input textbox irrespective datatype of the property which is getting bind with the control.
EditorFor: This control is bit smart. It renders HTML markup based on the datatype of the property. E.g. suppose there is a boolean property in model. To render this property in the view as a checkbox either we can use CheckBoxFor or EditorFor. Both will be generate the same markup.
What is the advantage of using EditorFor?
As we know, depending on the datatype of the property it generates the html markup. So suppose tomorrow if we change the datatype of property in the model, no need to change anything in the view. EditorFor control will change the html markup automatically.
The Html.TextboxFor always creates a textbox (<input type="text" ...).
While the EditorFor looks at the type and meta information, and can render another control or a template you supply.
For example for DateTime properties you can create a template that uses the jQuery DatePicker.
This is one of the basic differences not mentioned in previous comments:
Readonly property will work with textbox for and it will not work with EditorFor.
#Html.TextBoxFor(model => model.DateSoldOn, new { #readonly = "readonly" })
Above code works, where as with following you can't make control to readonly.
#Html.EditorFor(model => model.DateSoldOn, new { #readonly = "readonly" })
There is also a slight difference in the html output for a string data type.
Html.EditorFor:
<input id="Contact_FirstName" class="text-box single-line" type="text" value="Greg" name="Contact.FirstName">
Html.TextBoxFor:
<input id="Contact_FirstName" type="text" value="Greg" name="Contact.FirstName">

Required Attribute for bool value type when used as checkbox

I'm running into a problem where I have a simple add/edit form and using client-side validation (jQuery/MicrosoftMvcJQueryValidation.js) which is generated from data annotations and enabled client side by calling the following in my view:
<% Html.EnableClientValidation(); %>
This seems to work fine for most elements, however I have an instance where I have a boolean property which is rendered as a checkbox using:
<%= Html.EditorFor(model => model.Chargeable)%>
Which can be either true/false (ticked/unticked).
As the bool is a value type, and not nullable, it is being rendered as a required property and displays an error (client side) when the form is submitted reading "The Chargeable field is required.", however, as the HTML that is generated is two part (both checkbox and hidden value) it will pass the post back validation.
After browsing the MVC 2 source code, I've managed to put a "quick and dirty" fix in for the moment, which is to set:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Any one else got any ideas or suggestions on how I can get around this?
IMO, I dont think MVC should be setting the client-side required validator for checkboxes rendered using the Html.EditorFor/Html.CheckBox(For) methods.
Note: I'm using the ASP.NET MVC 2 RC2 and the MicrosoftMvcJQueryValidation.js from the matching MVC Futures release.
I suppose the easiest way of handling it is to call the rules("remove", [rules]) function on the elements (mainly checkboxes) that I want to remove the client-side validation from:
<script type="text/javascript">
$(document).ready(function() {
$('#Chargeable').rules('remove', 'required');
});
</script>

Resources