How do I let the RegularExpression accept nothing or only numbers.
At this moment it only accepts numbers. But if I don't enter anything it gives me the standard error: "The Seconds between refreshes field is required."
I want the user to be able to fill in nothing. (My application makes standard values.)
I couldn't find this on other questions. Only white spaces.
[RegularExpression("([1-9][0-9]*)", ErrorMessage = "Test, ErrorMessage from RegularExpression")]
public int NumberOfSecondsBetweenRefresh { get; set; }
My view:
#using (Html.BeginForm("Settings_Personal", "Home", FormMethod.Post))
{
#Html.ValidationSummary()
#Html.LabelFor(x => x.NumberOfSecondsBetweenRefresh)
#Html.TextBoxFor(x => x.NumberOfSecondsBetweenRefresh)
<input type="submit" value="Opslaan" />
}
Related
I have a basic form allowing users to input details which then gets posted and saved to a database - this works as expected without any issues:
#model R32.Register.Models.RegisterCar
#{
ViewBag.Title = "Edit Your R32";
}
<h2>Edit R32</h2>
<div>
#using (Html.BeginForm("UpdateCar", "Garage", FormMethod.Post))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Enter details</legend>
<ol>
<li>
#Html.LabelFor(m => m.NumberPlate)
#Html.EditorFor(m => m.NumberPlate, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.NumberPlate)
</li>
<li>
#Html.LabelFor(m => m.Edition)
#Html.EnumDropDownListFor(m => m.Edition, "Select an edition:", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Edition)
</li>
<li>
#Html.LabelFor(m => m.Colour)
#Html.EnumDropDownListFor(m => m.Colour, "Select a colour:", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Colour)
</li>
</ol>
<input type="submit" value="Save Changes" />
</fieldset>
}
</div>
Model snippet:
[Required]
[Display(Name="Edition")]
public MkEnum? Edition { get; set; }
Enum:
public enum MkEnum
{
[Display(Name="Mk4")]
Mk4 = 1,
[Display(Name="Mk5")]
Mk5 = 2
}
The control renders as expected, with the Edition dropdownlist having three values: "Select an edition", "Mk4", and "Mk5".
The user is able to select an edition, control is validated, then posted to the controller.
The Post is successful, and all selected values are sent to the controller - the app then persists the data in a database, and so on, without any problems.
The issue is when I pass this model back into the same View to allow the user to edit the saved data, the saved values for the enums are NOT being set as the selected value in the dropdownlist.
I can confirm that any saved string values, such as NumberPlate in this example, are being passed back into the view and loaded into the UI.
Putting a breakpoint on the viewmodel as it renders I can confirm that my #model contains the saved values for enum properties - Edition for example - but the end result is that the "Select an edition:" dropdown list is rendered containing the expected dropdown values, but it's value is the default "Select an edition:" instead of the actual value passed in via. m.Edition.
I have been able to get this working using DropDownListFor - but am having difficulties in understanding why this is not working using EnumDropDownListFor, as this clearly seems like a more elegant solution.
Does anyone have any help/advice for this?
I just ran into this problem myself. This happens because fields of type enum are being passed back to the browser serialized as their enum names, but #Html.EnumDropDownListFor generates its option values as integers. The browser can't match up the two so the dropdown stays at its default selection.
There are 3 ways to get around this.
Get the view model's enum field to serialize properly as an int.
Write a dropdown generator that uses enum names as option values.
Use javascript to manually select the option (includes razor syntax here)
$("#YourDropdownID option").each(function () {
if ($(this).html() == '#(Html.DisplayFor(o => o.YourEnumFieldName))') {
$(this).attr("selected", "selected");
return;
}
});
Ok, so from what I could see the problem was caused by using an ActionLink to pass back the full model of an item being edited. Everything was being sent back in a Query string, so my Enum values were being passed to the controller in the following way: mkEnum=Mk4.
I was then loading the UpdateCar view as seen above in my example - but the query string values were being persisted in the call back to the View.
EnumDropDownListFor is unable to interpret/convert the text value of enums into their actual values - if I manually edited the Query string to mkEnum=1, then the correct value wasloaded into the ViewModel.
In addition to this problem, it was not a good solution passing the full model back to the controller.
I've modified the code to pass back a single Id of the item being edited - the controller then verifies the user has access to that Id, retrieves the Model from the Database then passes it back to the same View as in my above example.
With this change my dropdowns are now being updated with their values without any issues.
TLDR; If you experience this issue check to make sure you don't have model properties, specifically enum values represented by their string values, in a query string when loading your view and using EnumDropDownListFor.
I'm having difficulty writing a custom remote validator that will evaluate distinct pairs of fields from a list? The list has 2 fields that need to be validated: Description and Amount. This is my list.
#for (int i = 0; i < Model.MyList.Count(); i++)
{
#Html.TextBoxFor(m => m.MyList[i].Description)
#Html.TextBoxFor(m => m.MyList[i].Amount)
#Html.ValidationMessageFor(m => m.MyList[i].Description)
#Html.ValidationMessageFor(m => m.MyList[i].Amount)
}
The validation rules are as follows:
Amount must be zero or greater. It cannot be blank.
Description is required only when an amount is greater than zero.
When description is entered, the amount must be greater than zero.
I've seen (and implemented) solutions like these, but they don't address this type of scenario of evaluating multiple distinct pairs of fields that are in a list.
Multiple fields validation using Remote Validation
how to use multiple AdditionalFields in remote validation - asp.net mvc
This is in my model. And the validation rules for Amount work. But the custom remote validator (ValidateDescriptionAmountPair) for Description fails.
[Range(0, int.MaxValue, ErrorMessage = "Amount must be 0 or greater.")]
[Required(ErrorMessage = "Amount is required.", AllowEmptyStrings = false)]
public decimal Amount { get; set; }
[Remote("ValidateDescriptionAmountPair", "MyController", AdditionalFields = "Amount")]
public string Description { get; set; }
This is my custom validator.
[HttpGet]
public virtual JsonResult ValidateDescriptionAmountPair(string Description, string Amount)
{
bool isOkay = true;
string reasonItsInvalid = string.Empty;
// TODO: Add code to evaluate business rules, and change
// isOkay and reasonItsInvalid accordingly.
if (isOkay)
{
return Json(true, JsonRequestBehavior.AllowGet);
}
else
{
return Json(reasonItsInvalid, JsonRequestBehavior.AllowGet);
}
}
I put a breakpoint in ValidateDescriptionAmountPair. This method gets called, but the Description and Amount values arrive as NULL rather than with expected values.
These are some markup examples for fields rendered in the view.
<input data-val="true" data-val-remote="'Description' is invalid." data-val-remote-additionalfields="*.Description,*.Amount" data-val-remote-url="/MyController/ValidateDescriptionAmountPair" id="MyList_0__Description" name="MyList[0].Description" type="text" value="Paid for this" aria-invalid="false">
<input class="form-control text-right" value="5000.00" data-val="true" data-val-number="The field Amount must be a number." data-val-range="Amount must be 0 or greater." data-val-range-max="2147483647" data-val-range-min="0" data-val-required="Amount is required." id="MyList_0__Amount" name="MyList[0].Amount" placeholder="Dollar Amount" style="width:100px;" type="text" aria-required="true" aria-invalid="false" aria-describedby="MyList_0__Amount-error">
<input data-val="true" data-val-remote="'Description' is invalid." data-val-remote-additionalfields="*.Description,*.Amount" data-val-remote-url="/MyController/ValidateDescriptionAmountPair" id="MyList_1__Description" name="MyList[1].Description" type="text" value="test" aria-invalid="false" aria-describedby="MyList_1__Description-error">
<input class="form-control text-right" value="10000.00" data-val="true" data-val-number="The field Amount must be a number." data-val-range="Amount must be 0 or greater." data-val-range-max="2147483647" data-val-range-min="0" data-val-required="Amount is required." id="MyList_1__Amount" name="MyList[1].Amount" placeholder="Dollar Amount" style="width:100px;" type="text" aria-required="true" aria-invalid="false" aria-describedby="MyList_1__Amount-error">
<input data-val="true" data-val-remote="'Description' is invalid." data-val-remote-additionalfields="*.Description,*.Amount" data-val-remote-url="/MyController/ValidateDescriptionAmountPair" id="MyList_2__Description" name="MyList[2].Description" type="text" value="Paid for that" aria-invalid="false">
<input class="form-control text-right" value="20000.00" data-val="true" data-val-number="The field Amount must be a number." data-val-range="Amount must be 0 or greater." data-val-range-max="2147483647" data-val-range-min="0" data-val-required="Amount is required." id="MyList_2__Amount" name="MyList[2].Amount" placeholder="Dollar Amount" style="width:100px;" type="text" aria-required="true" aria-invalid="false" aria-describedby="MyList_2__Amount-error">
What I think may be happening is that the names applied to list entries don't exactly match the "Description" and "Amount" parameter names in ValidateDescriptionAmountPair(), because they have indexes applied to the names. In other words, the field names are MyList[1].Description and MyList[1].Amount, but the ValidateDescriptionAmountPair() method is looking for Description and Amount. That's just a hunch which could be totally off base. If indeed that's why it fails, then what is the solution?
At any rate, I need to be able to implement the business rules noted above, and I would prefer to do this using an MVC data annotation or custom remote validation approach rather than hand-rolling some client-side jQuery to do this. Thanks for your help.
I could not achieve this in remote validation. But you achieve this using controller and #Html.ValidationSummary()
Add #Html.ValidationSummary() in view
#Html.ValidationSummary();
#for (int i = 0; i < Model.MyList.Count(); i++)
{
#Html.TextBoxFor(m => m.MyList[i].Description)
#Html.TextBoxFor(m => m.MyList[i].Amount)
#Html.ValidationMessageFor(m => m.MyList[i].Description)
#Html.ValidationMessageFor(m => m.MyList[i].Amount)
}
In Controller check the logic for distinct value and add the error message to the summary
[HttpPost]
public ActionResult MultipleValidation(List<MyList> model)
{
bool isOkay = true;
string reasonItsInvalid = string.Empty;
// TODO: Add code to evaluate business rules, and change
// isOkay and reasonItsInvalid accordingly.
if (!isOkay)
{
// Message to display in validation summary
ModelState.AddModelError("", "Duplicate Record");
}
return View("View", model);
}
I have the following textboxfor in my view
#Html.TextBoxFor(m => m.AdvertModel.Title, new
{
#class = "form-control",
type = "text",
placeholder = "Enter a descriptive title about the item for sale",
id = "Enter a descriptive title",
data_val_required = "The Title field is required.",
data_val = "true"
})
You can see I have added the data_val_required and data_val attributes to do it, this renders as follows:
<input id="Enter a descriptive title" class="form-control" type="text" value="" placeholder="Enter a descriptive title about the item for sale" name="Title" data-val-required="The Title field is required." data-val-maxlength-max="100" data-val-maxlength="The field Title must be a string or array type with a maximum length of '100'." data-val="true">
When I run the application and this and leave it empty and click submit the ModelState.isValid is always true, when I would expect it to be false, why does it keep saying it true?
When you submit a form to a POST method, the form values contain key/value pairs consisting of each controls name attribute and value attribute. In your case it would be AdvertModel.Title=The value entered in the textbox. No information regarding other attributes in controls are sent to the server.
The data-* attributes are rendered by the html helpers based on validation attributes applied to the model and are useful only if you have the associated #Html.ValidationMessageFor() and include the relevant script files (jquery, jquery.validate and jquery.validate.unobtrusive).
You will get both server side and client side validation if you include the [Required] attribute on the model property
[Required(ErrorMessage = "The Title field is required.")]
public string Title { get; set; }
and in the view
#Html.TextBoxFor(m => m.AdvertModel.Title, new { #class = "form-control", placeholder = "Enter a descriptive title about the item for sale", title = "Enter a descriptive title" })
#Html.ValidationMessageFor(m => m.AdvertModel.Title)
Side notes: You do not need type="text" (this is added by the helper) and I assume id = "Enter a descriptive..." is a typo and that its really title = "Enter a descriptive..."
So I have this form where the user can enter in a start time and end time (for a booking). The values in the database are DateTimes, but the Date part is completely ignored. Currently, when I enter in eg. "5:00 pm" (through a jQuery time picker), it says this is not a valid date. If I type "30/1/2013 5:00 pm" it accepts this as valid... How do I change this behaviour to only validate as a time? (or if that's not ideal, how can I completely turn validation off for that field - I'll manually handle validation in the controller)
I saw this: http://connect.microsoft.com/VisualStudio/feedback/details/705643/a-data-val-date-attribute-is-generated-for-time-fields-in-asp-net-mvc-4# but Microsoft claims it has been fixed; not sure if this is the same problem. I don't want to change the database definition to TimeSpan because I believe it will muck up the existing data (it will won't it?).
Controller:
[HttpPost]
public ActionResult Create(BookingDetailsDate bookingdetailsdates) //, FormCollection collection)
{
if (ModelState.IsValid)
{
try
{
//bookingdetailsdates.StartTime = DateTime.Parse(collection["StartTime"]); // TODO: do this better
//bookingdetailsdates.EndTime = DateTime.Parse(collection["EndTime"]);
bookingdetailsdatesRepository.Add(bookingdetailsdates);
bookingdetailsdatesRepository.Save();
return RedirectToAction("Index", new { id = bookingdetailsdates.BookingDetailsID });
}
catch { }
}
return View(bookingdetailsdates);
}
View:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend></legend>
...
#Html.EditorFor(model => model.StartTime)
#Html.EditorFor(model => model.EndTime)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Editor Template:
<div class="editor-label">
#Html.LabelFor(m => m)
</div>
<div class="editor-field">
#if (Model.HasValue==true)
{
#Html.TextBox("", Model.Value.ToShortTimeString(), new { #class = "TimePicker" })
}
else
{
#Html.TextBoxFor(m => m, new { #class = "TimePicker" })
}
#Html.ValidationMessageFor(m => m)
</div>
I think "DateTime" this data type is not a good choice, if you just want to save time that users save and then compare them in somewhere I suggest to use "nchar" type. Why? Let me explain, datetime is a very complicated type, it has many kinds of forms. Like "2013-1-29 5:00 pm", "2013/1/29 5:00pm". If your purpose is to compare and check if out of date, you can use this way. "201301291700", it's a fixed length which is 12. The benefit of this is 1. you can easy to save it anywhere by type string. 2. you can compare easily by convert to int type or maybe long type.(number is much easier to compare, isn't it?)
Answer is based on my experience, hope it helps you!
So the trouble was in jQuery's validation, even though the metadata for my fields specified it would be a time only (and that wasn't even strictly necessary), jQuery's validate requires the box to contain a full datetime string...
Commenting out these lines fixes the problem:
<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>
I am using an EditorTemplate for a DateTimeOffset field that consists of...
#model DateTimeOffset?
#Html.TextBox("", String.Format("{0:u}", Model.HasValue ? Model : DateTimeOffset.UtcNow), new { #class = "datepicker" })
This works in 90% of my forms, I get values like 2012-07-31 11:30:09Z. However, I have one form that will not apply any formatting. The HTML output of the working input field and the non-working input field are the same.
Working...
<input class="datepicker hasDatepicker" data-val="true" data-val-required="'Launch Time' must not be empty." id="LaunchTime" name="LaunchTime" type="text" value="2012-07-31 11:30:09Z">
Non-working...
<input class="datepicker hasDatepicker" data-val="true" data-val-required="'Launch Time' must not be empty." id="LaunchTime" name="LaunchTime" type="text" value="07/31/2012 11:30:09 +00:00">
The only thing that I have found that fixes the problem is to change the TextBox name field...
#Html.TextBox("asdf", String.Format("{0:u}", Model.HasValue ? Model : DateTimeOffset.UtcNow), new { #class = "datepicker" })
However, this then changes my input field to...
<input class="datepicker hasDatepicker" id="LaunchTime_asdf" name="LaunchTime.asdf" type="text" value="2012-07-31 11:30:09Z">
which will then break the form submission, and removes the validation rules.
The model...
[DisplayFormat(DataFormatString = "{0:u}" , ApplyFormatInEditMode = true)]
public DateTimeOffset LaunchTime { get; set; }
The problem is that the only format that seems to work for the datetime value is yyyy-mm-dd. /s do not work.