I have the following model property
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:d/M/yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Date of Screening")]
public DateTime? ScreeningDate { get; set; }
and the following view:
#Html.TextBoxFor(model => model.ScreeningDate, new { #class="date maintainState" })
and yet I get this markup for the textbox:
<input value="18/06/2013 12:00:00 AM" class="date maintainState" ... type="text" />
I want the value to be 18/06/2013
It works when I apply #Html.EditorFor, but I need control over the class attribute. What am I doing wrong? Thank you very much.
It works when I apply #Html.EditorFor, but I need control over the
class attribute. What am I doing wrong?
Nothing, it's how things work. Only the EditorFor and DisplayFor helpers respect the [DisplayFormat] attribute.
I understand that you are using TextBoxFor because you want to apply a custom class to the field which is what the EditorFor doesn't allow you to. But that's not true. All that the EditorFor helper does is to render the corresponding editor template. And if you do not have a custom template it renders the default one.
So what?
Well, you write a custom editor template for the DateTime type that will behave as you want. Just like that in ~/Views/Shared/EditorTemplates/DateTime.cshtml:
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, ViewData)
And then simply:
#Html.EditorFor(model => model.ScreeningDate, new { #class="date maintainState" })
Now killed 2 rabbits with one bullet:
We applied the desired format
We applied the desired class to the input field
And if you wanna kill a third rabbit and be able to validate this custom format when the form is submitted back (because remember that the default model binder doesn't care much about this [DisplayFormat] attribute) you could write a custom model binder that will respect the [DisplayFormat] attribute, just as I explained here: https://stackoverflow.com/a/7836093/29407
Related
If I do the following
ViewModel:
public class ToleranceInput{
public decimal Tolerance{get;set;}
}
And in my views
AssignTolerances.cshtml
#model ToleranceInput
#using (#Html.BeginForm("AssignTolerances", Tolerances", FormMethod.Post, new {#class="form-horizontal"}))
{
#Html.ValidationSummary()
#Html.Partial("_AssignOrEditTolerances", Model)
<div class="form-actions">
<button type="submit">
<i class="icon-ok icon-white"></i> Save
</button>
</div>
}
_AssignOrEditTolerances.cshtml:
#model ToleranceInput
#Html.TextBoxFor(a=>a.Tolerance)
#Html.ValidationMessageFor(a=>a.Tolerance)
The standard MVC validation works correctly. When I type in letters (instead of numbers) it shows a red error message as it should. However, in the viewmodel if I change Tolerance to a nullable decimal? it does not work correctly. if I type a non-decimal such as 'asdf' in the textbox I see a quick flash of the red validation messsage when I hit the save button, but then the POST goes through and the [HttpPost] AssignTolerances method in my controller gets executed. Why is this happening? Any ideas?
Edit: I have just found the following link. Looks like the strings get converted to nulls and the workaround looks horrible: Integer validation against non-required attributes in MVC
Have you also considered adding the check in the controller action?
[HttpPost]
public ActionResult TestPost(ToleranceInput model)
{
if(!ModelState.IsValid)
{
return View(model);
}
}
And then simply add validation into your Model, such as the [Required] attribute
I am building a dropdownlist using the answer here: SelectListItem with data-attributes. This will allow me to add a different class and data annotations to different <option>'s
However I am struggling with building the <select> initially. I have
<select name="#Html.NameFor(a=>a.ValueType)"
id="#Html.IdFor(a=>a.ValueType)">
</select>
My ViewModel looks like
[Required(ErrorMessage = "Value Type is required")]
public string ValueType { get; set; }
How do I get the Required annotation validation into the view?
The final html in the browser should look like:
<select id="ValueType" name="ValueType" data-val-required="Value Type is required" data-val="true"></select>
but I currently have:
<select id="ValueType" name="ValueType"></select>
Is there a #Html method to get these data-val from the ViewModel attributes or how do i do this? Do I have to hard-code it?
I want to pass other value when checkBox is clicked.
my code is as below
foreach (var item in Model) {
<td>
#Html.CheckBox("Project", false, new { item.ProjectId})
</td>
}
Controller is
[HttpPost]
public ActionResult Test(FormCollection collection)
{
var test = collection["Project"]; }
in Var test i am getting True or False
Is there any way to get ProjectId??
The CheckBox and CheckBoxFor helpers are meant for bool and bool? properties (In fact, if you look at the source code you will see they force a casting of the property value to bool?. Check the method InputHelper here in the source code).
In the case of the CheckBox helper, the output will be something like this:
<input id="Foo" name="Foo" type="checkbox" value="true">
<input name="Foo" type="hidden" value="false">
As you can see, the values are hardcoded to true/false boolean values. You could override the value attribute but that would only apply to the checkbox and not to the hidden field with the value for when the checkbox is unchecked. Using the helper with non-boolean fields would also lead you to trouble because of the casting to bool? I mentioned above.
One possible solution would be to manually create the desired html. (You need to be carefull with the name attribute here as it is what the MVC model binder will use to populate your model). Writing something like this in your view:
<input id="Foo" name="Foo" type="checkbox" value="#item.ProjectId">
#* you could add another hidden input for when the checkbox is not checked *#
If you are using the model metadata or if you have complex bindings, this may be a problem as you would need to manually set the html attributes and be careful with the name attribute.
Another option is to create your own html helper. This could allow you to use other types not just booleans and should expect a value for when the checkbox has been checked. The idea is to create something like this:
public static class CustomHelpers
{
public static MvcHtmlString CheckBoxNonBooleanFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object checkedValue)
{
var fieldName = ExpressionHelper.GetExpressionText(expression);
var fullBindingName = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(fieldName);
var fieldId = TagBuilder.CreateSanitizedId(fullBindingName);
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var value = metadata.Model;
TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("name", fullBindingName);
tag.Attributes.Add("id", fieldId);
tag.Attributes.Add("type", "checkbox");
tag.Attributes.Add("value", (checkedValue ?? true).ToString());
if ((checkedValue != null && checkedValue.Equals(value))
||(checkedValue == null && value == null ))
{
tag.Attributes.Add("checked", "checked");
}
var validationAttributes = html.GetUnobtrusiveValidationAttributes(fullBindingName, metadata);
foreach (var key in validationAttributes.Keys)
{
tag.Attributes.Add(key, validationAttributes[key].ToString());
}
return new MvcHtmlString(tag.ToString());
}
}
This helper can be used in your view as in the following example (Don´t forget to include your helper namespace into the views namespaces settings of the web.config in the views folder):
#Html.CheckBoxNonBooleanFor(m => m.Foo, 132)
And it will generate the following html, taking care of things like the metadata attributes, the name, the checked attribute, etc for you.
<input id="Foo" name="Foo" type="checkbox" value="132" data-val="true" data-val-number="The field Foo must be a number.">
If needed, you could easily extend it adding another parameter uncheckedValue that will add a hidden input field with the desired value for when the checkbox remains unchecked. You could also add the htmlAttributes parameter to allow you passing additional random html attributes.
As a final comment, just double check that radio buttons won´t be a fit for your requirements, as you could easily have multiple radio buttons for the same field with different int values.
I'm assuming you want the projectid given a checkbox is checked?
<td>
#Html.Hidden("projectId", item.ProjectId)
#Html.CheckBox("selected", false)
</td>
[HttpPost]
public ActionResult Test(int projectId, bool selected)
{
if (selected)
{
///use your projectId
So imagine this:
There is a View.
There is a model with this view in the following form:
Id
List<Food>
within each Food, there is:
Id
Name
List<Ingredients>
each ingredient contains:
Id
Name
Qty
This is in 1 model.
I have a view which takes in this Model.
I then have a partial view which takes in the List and renders it on the screen.
That works however when the form is submitted (the button is on the main view), the data fails to bind/is not shown in the Model.
what is the correct way to be able to bind the data back?
it does work when I take the whole thing and put it in the main view itself but due to reusability reasons, it makes sense having it in a partial view so I can just "drop" it on any page and pass the data.
The partial view takes in this:
#model List<FoodProject.Web.Models.FoodViewModel>
Thanks
UPDATE
I tried using the EditorTemplate and it seems to almost respect the model binding conventions as before using the Html.Partial was not doing so. That was producing things like:
[0].PropertyName
instead of:
ModelName[0].PropertyName
The template editor is almost there but gives me:
ModelName.[0].Id
I believe this is why when posting, I get null back in the model collection
how can I make it respect the model binding? where am I going wrong?
You should be close with the Editor Template because that worked for me. I'll show my example and maybe it will help you see what you have wrong.
The Models:
public class TestModelA
{
public List<TestModelB> PropA { get; set; }
}
public class TestModelB
{
public string PropB { get; set; }
}
The Editor Template (TestModelB.cshtml) placed in Views/Shared/EditorTemplates:
#model MvcTest.Models.TestModelB
#Html.EditorFor(m => m.PropB)
The main view:
#model MvcTest.Models.TestModelA
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.PropA)
<input type="submit" value="Submit" />
}
I am using Kendo UI mvc grid for Data listing. I am making InLine Editing in this Grid.I am using EditorTemplate for DateTime field, so that it will give datetimepicker for DateTime field in InLine Edit Mode.When i am going to Click on Update button, it will give me Validation message like this : 'The must be a date'
columns.Bound(k => k.SevenDaysFrom).Format("{0:dd.MM.yyyy}").EditorTemplateName("DateTime").Width(30);
columns.Bound(k => k.SevenDaysTo).Format("{0:dd.MM.yyyy}").EditorTemplateName("DateTime").Width(30);
here DateTime in EditorTemplateName("DateTime") is the Template file i.e DateTime.cshtml
And this file will contain the Following code :
#model DateTime?
#(Html.Kendo().DateTimePickerFor(m => m))
Now it will give the validation error message while clicking on Update.The Belowe attach is the Validation error :
So, why this is happening is not known to me?
What is the solution for this ? Please Help.
Set the kendo culture:
#{
var culture = "en-GB";
}
<script src="#Url.Content("~/Scripts/kendo/cultures/kendo.culture." + #culture + ".min.js")"></script>
<script> kendo.culture("#culture"); </script>
You should mention the data type in View Model
[DataType(DataType.Date)]
public Nullable<DateTime> SevenDaysFrom { get; set; }
and in kendo Grid you can mention like below,
columns.Bound(k => k.SevenDaysFrom).Format("{0:dd.MM.yyyy}")
refer my another answer
Display only datepicker in kendo inline editing not datetime picker