Data annotation on int[] - validation

In a ASP.NET MVC5, I'm using the chosen JS library for a multi-dropdown select. How Can I do to use Data Annotation to validate the field?
Actually I use [Required] on all fields, this multi-dropdown select too, but it isn't working.
Code:
[MinLength(1)]
public int[] fields{ get; set; }
Here is my Code in the cshtml:
#Html.ListBoxFor(x => x.fields, Model.fieldsSelect, new { data_placeholder = "pholder" })
#Html.ValidationMessageFor(model => model.fields, "", new { #class = "text-danger" })
Without the plugin I currently use (chosen) there is no validation , Here is the HTML rendered without chosen:
<div class="col-md-10">
<select data-placeholder="Enter multiple fields" data-val="true" data-val-minlength="The field fieldsmust be a string or array type with a minimum length of '1'." data-val-minlength-min="1" id="fields" multiple="multiple" name="fields">
<option value="944454">WARUYFJGHIE</option>
<option value="33033095">WEBJKHGJHGVHGAN</option>
</select>
<span class="field-validation-valid text-danger" data-valmsg-for="fields" data-valmsg-replace="true"></span>
</div>
Validation works for all my string but not this one: when I select nothing on the form, all [Required] for strings works: an error message is apparing and submit is not hitting the controller/server, but not the [MinLength(1)]... No error message and when I fill all except [MinLength(1)], the form is submitting and error occurs in the controller/server because of null.
Versions of JS validations:
jQuery Validation Plugin - v1.11.1 - 3/22/2013
jquery.validate.unobtrusive.min.js : no version (neither in the
jquery.validate.unobtrusive..js)

You can use the MinLengthAttribute
[MinLength(1)]
public int[] fields{ get; set; }
Edit
Based on additional comments, a jquery plugin is being used that hides the <select>. By default hidden fields are not validated. To include hidden fields, add the following
$.validator.setDefaults({
ignore: []
});

Related

How to bind a list of objects in ASP.NET Core MVC when the posted list is smaller than original?

Using "disabled" attribute on inputs on form does not post them, which is expected and wanted. However, if you prepare a form of 3 objects in a list, disable the first and third, and submit, the 2nd object appears in post header, but does not bind to the list correctly, because it has an index [1] instead of [0].
I understand how model binding works and why it does not bind the posted object that I want, but I don't know how else to describe the problem to get specific results that would lead me to my solution. Anything I search for leads to basic post and binding examples.
List inside the model I'm using:
public IList<_Result> Results { get; set; }
Class _Result has one of the properties:
public string Value { get; set; }
I fill up the list and use it in view like so:
#for (int i = 0; i < Model.Results.Count; i++)
{
...
<td>
<input asp-for="Results[i].Value" disabled />
</td>
...
}
I have checkboxes on form, which remove (with javascript) the "disabled" attribute from the inputs and thus allow them to be posted.
When I fill up the said list with 3 _Result objects, they are shown on form and all have the "disabled" attribute. If I remove the "disabled" attribute from the first two objects and click on submit button, I receive the Results list with first 2 _Result objects, which is as expected.
However, if I remove the "disabled" attribute only from the second _Result object (the first _Result object still has "disabled" attribute), the Results list comes back empty in my Controller method.
In my Form Data Header, I see this: "Results[1].Value: Value that I want posted", which means that post occurs, but list does not bind the object due to the index.
Any idea on how I can achieve that proper binding? Also, the reason I'm using "disabled" attribute is because I'm showing many results on a single page and want to only post those that are selected.
For getting selected items, you could try checkbox with View Model instead of using jquery to control the disable property.
Change ViewModel
public class ModelBindVM
{
public IList<_ResultVM> Results { get; set; }
}
public class _ResultVM
{
public bool IsSelected { get; set; }
public string Value { get; set; }
}
Controller
[HttpGet]
public IActionResult ModelBindTest()
{
ModelBindVM model = new ModelBindVM
{
Results = new List<_ResultVM>() {
new _ResultVM{ Value = "T1" },
new _ResultVM{ Value = "T2" },
new _ResultVM{ Value = "T3" }
}
};
return View(model);
}
[HttpPost]
public IActionResult ModelBindTest(ModelBindVM modelBind)
{
return View();
}
View
<div class="row">
<div class="col-md-4">
<form asp-action="ModelBindTest">
#for (int i = 0; i < Model.Results.Count; i++)
{
<input type="checkbox" asp-for="Results[i].IsSelected" />
<label asp-for="#Model.Results[i].IsSelected">#Model.Results[i].Value</label>
<input type="hidden" asp-for="#Model.Results[i].Value" />
}
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>

DropDown list issue in knockout js asp.net mvc 3

I have the following problem. I'm developing web application on asp.net mvc and using KnockoutJS in one of views. I have the following viewmodel
public class ExampleViewModel
{
public IEnumerable<Element> ElementsList { get; set; }
}
class Element
{
public bool Required {get;set;}
}
option Required must be set with dropdown list. I have the following block code in view
<div data-bind="foreach: ElementsList">
<select data-bind="attr: { name: 'ElementsList[' + $index() + '].Required' }, value: Required">
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</div>
when I select Yes or No from drop down and submit form I have appropriate value saved in database, but when I open this view in browser after that all values in drop down list are 'Yes'. Despite the fact that when I open view and debug it I can see with Quick Watch, that each value from ElementsList has correct value of Required option ('Yes' or 'No'), all dropdown lists have a value 'Yes'.

How to add unobtrusive validation for html template fields whats not in the model

i got a template created for custom zip code field.
My template code is below:
#{
string model = Model ?? string.Empty;
string zipFirst = "";
string zipSecond = "";
if(!String.IsNullOrEmpty(model) && !String.IsNullOrWhiteSpace(model))
{
var values = model.Split('-');
if(values.Count() == 2)
{
zipFirst = values[0] ?? string.Empty;
zipSecond = values[1] ?? string.Empty;
}
}
var pName = ViewData.ModelMetadata.PropertyName;
var zipAreaId = "#" + pName + "zipcodearea";
}
<div id="#(pName)zipcodearea">
<input type="text" maxlength="5" id="zipcodefirst" name="#(pName)codefirst" value="#(zipFirst)" style="width:136px"/> -
<input type="text" maxlength="4" id="zipcodesecond" name="#(pName)codesecond" value="#(zipSecond)" style="width:120px"/>
#Html.HiddenFor(m => m, new { #class = "generatedZipField"})
</div>
<script type="text/javascript">
jQuery(function ($) {
$('#(zipAreaId) #zipcodefirst').autotab({ target: '#(pName)codesecond', format: 'numeric' });
$('#(zipAreaId) #zipcodesecond').autotab({ previous: '#(pName)codefirst', format: 'numeric' });
$('#(zipAreaId)').zipcode();
});
</script>
And i use it like this:
[UIHint("ZipCode")]
[Display(Name = "Zip Code")]
public string Zip { get; set; }
Like you see in my template i got two fields whats not included in the model.
It is #zipcodefirst and #zipcodesecond.
What i need to achieve is to have two separate fields for full us zip code.
When user fill both fields im using jquery widget for merging them into one string and inserting it into hidden field in template. after form submited value in hidden field getting sent into server.
Whats the problem?
I need to add mvc unobtrusive validation for them two fields whats not in the model #zipcodefirst and #zipcodesecond.
validation rules
zipcodefirst field must be filled in first
then zipcodefirst field is filled you can fill second field
second field must have 4 digits in it
first field must have five digits
cant fill second field while first one is empty or incorectly filled
Im strugling with validation part for quite a while now.... :(
How i could achieve that thru mvc3 unobtrusive validation tools?
any help will be highly apreciated guys.
Add unobrusive data data validation on the textbox by adding data-val="true" and use a regular expression for your zip code.
<input type="text" data-val="true" data-val-regex="Invalid zip code format" data-val-regex-pattern="YOUR REGEXP HERE" />
UPDATE
If you also want it to be required you can add the data-val-required attribute.
<input type="text" data-val="true" data-val-requred="Zip code is required" data-val-regex="Invalid zip code format" data-val-regex-pattern="YOUR REGEXP HERE" />
More information about validation in MVC 3:
http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html

MVC3 Modelbinder EF4 ICollection property [duplicate]

I'm working on my first ASP.NET MVC 3 application and I've got a View that looks like this:
#model IceCream.ViewModels.Note.NotesViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.TextBoxFor(m => m.Name)
foreach (var item in Model.Notes)
{
#Html.EditorFor(m => item);
}
<input type="submit" value="Submit"/>
}
And I have an EditorTemplate that looks like this:
#model IceCream.ViewModels.Note.NoteViewModel
<div>
#Html.HiddenFor(m => m.NoteID)
#Html.TextBoxFor(m => m.NoteText)
#Html.CheckBoxFor(m => m.IsChecked)
</div>
NotesViewModel looks like so:
public class NotesViewModel
{
public string Name { get; set; }
public IEnumerable<NoteViewModel> Notes { get; set; }
}
NoteViewModel looks like this:
public class NoteViewModel
{
public int NoteID { get; set; }
public System.DateTime Timestamp { get; set; }
public string NoteText { get; set; }
public bool IsChecked { get; set; }
}
The NotesViewModel is populated just fine when it is passed to the view. However when the submit button is clicked, the controller action handling the post has only the value for the Name property of the viewmodel. The Notes property - the list of notes that have been checked/unchecked by the user - is null. I've got a disconnect between the populating of those TextBoxFor and CheckBoxFor elements when the view is displayed and the ViewModel being sent back. Guidance on this?
SOLUTION
Thanks go to Mystere Man for setting me straight on this. As I understand it, essentially by changing my loop to
#Html.EditorFor(m => m.Notes)
changes the underlying HTML, which I understand provides for the proper model binding on the post. Looking at the resulting HTML, I see that I get the following generated for one of the Notes:
<div>
<input id="Notes_0__NoteId" type="hidden" value="1" name="Notes[0].NoteId">
<input id="Notes_0__NoteText" type="text" value="Texture of dessert was good." name="Notes[0].NoteText">
<input id="Notes_0__IsChecked" type="checkbox" value="true" name="Notes[0].IsChecked>
</div>
Which is different than this HTML generated by my original code:
<div>
<input id="item_NoteId" type="hidden" value="1" name="item.NoteId>
<input id="item_NoteText" type="text" value="Texture of dessert was good." name="item.NoteText" >
<input id="item_IsChecked" type="checkbox" value="true" name="item.IsChecked">
</div>
By looping through the Notes, the generated HTML essentially loses any references to the viewmodel's Notes property and while the HTML gets populated correctly, the setting of the checkbox values has no way to communicate their values back to the viewmodel, which I guess is the point of the model binding.
So I learned something, which is good.
You're a smart guy, so look at your view. Then, consider how the HTML gets generated. Then, consider how on postback the Model Binder is supposed to know to re-populate Notes based on the generated HTML.
I think you'll find that your HTML doesn't have enough information in it for the Model Binder to figure it out.
Consider this:
#EditorFor(m => Model.Notes)
Rather than the for loop where you are basically hiding the context from the EditorFor function.
And for those that just want the answer as a for loop:
#for (int x = 0; x < Model.Notes.Count(); x++) {
#Html.HiddenFor(m => m.Notes[x].NoteId)
#Html.EditorFor(m => m.Notes[x].NoteText)
#Html.EditorFor(m => m.Notes[x].IsChecked)
}

asp.net MVC 3 - JQuery ajax $.get return <nonscript> reCaptcha instead of actual html in partial view

This problem is kind of difficult to explain, but I'll do my best.
I'm simply trying to render the reCaptcha input on a form that is embedded inside a partial view.
Here's how I'm obtaining the partial view with JQuery $.get:
GetAndRenderPartialContent: function (url, obj) {
$.get(url, function (data) {
obj.replaceWith(function () {
var content = "<div id=\"" + obj.attr('id') + "\">" + data + "</div>";
return content;
});
});
}
This works great as a JQuery extension method.
The URL that's passed in to this method is simply a controller route that returns a partial view like this:
public ActionResult GetSomeContent()
{
var model = new SomeModel();
// set modal values
// Finally return partial view
return PartialView("_MyPartialView", model);
}
This works great. It even renders form values bound to the model.
The problem is only with reCaptcha. In my view I have this line to render the reCaptcha:
#Microsoft.Web.Helpers.ReCaptcha.GetHtml(theme: "clean", publicKey: ConfigurationManager.AppSettings["reCaptcha:publicKey"], language: "en")
This works when I embed it directly in the parent view.However, when it is rendered from the partial view method, I get the following results:
<noscript>
<iframe frameborder="0" height="300px" src="http://www.google.com/recaptcha/api/noscript?k=[MY PUBLIC KEY REMOVED FOR DEMO]" width="500px"></iframe>
<br /><br />
<textarea cols="40" name="recaptcha_challenge_field" rows="3"></textarea>
<input name="recaptcha_response_field" type="hidden" value="manual_challenge" />
</noscript>
It appears that the PartialView method is HtmlEncoding the output from the reCaptcha, but not the other form elements that are embedded in the form. Has anyone encountered this or have an elegant solution to this annoying problem that has taken up a couple of hours of my time?
The only solution I've been able to achieve is to render the reCaptcha in the parent view, hide it until the partial view page is called, then relocate it to the appropriate position in the form, which is not a desirable nor elegant solution.
Any help is appreciated.
Thanks.
* UPDATE **
I tried pasting the view code here but stackoverflow's editor kept rejecting the code. Suffice it to say, there is nothing unusual about the view. The model contains properties for binding such as:
[Required]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[Display(Name = "Confirm Email Address")]
[Compare("Email", ErrorMessage = "Your email and confirmation email do not match.")]
public string ConfirmEmail { get; set; }
The form:
#using (Html.BeginForm("UpdateInfo", "MyAccount", FormMethod.Post, new { #id = "InfoForm" }))
Render the model items:
<div class="editor-label">
#Html.LabelFor(m => m.Email)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Email) #Html.ValidationMessageFor(m => m.Email)
</div>
Near the end of the form:
<fieldset id="reCaptchaFieldset">
<legend>Captcha Authorization</legend>
#ReCaptcha.GetHtml(theme: "clean", publicKey: System.Configuration.ConfigurationManager.AppSettings["reCaptcha:publicKey"])
</fieldset>
Try the following:
#Html.Raw(Microsoft.Web.Helpers.ReCaptcha.GetHtml(theme: "clean", publicKey: ConfigurationManager.AppSettings["reCaptcha:publicKey"], language: "en"))
Use the AJAX API part in this document:
http://code.google.com/apis/recaptcha/docs/display.html
Use this code in the partialView.

Resources