In MVC3 is it possible to have multiple EditorTemplates for the same type? - asp.net-mvc-3

I have some DateTime fields on my MVC model classes - some which require a Date as input and others that require a Time as input - but both are DateTime properties.
Is it possible to have an EditorTemplate for DateTime that somehow produces a date picker to properties that are meant to be dates, and a time picker for properties that are meant to be times?

Yes, here is one way:
In ~/Views/Shared/EditorTemplates (or ~/Views/Shared/DisplayTemplates, create template files that use your favourite view engine (example uses Razor/C#)
file Date.cshtml
replace this with a real date picker
file Time.cshtml
replace this with a real time picker
Then, in your model:
[UIHint("Date")]
public DateTime DateProperty { get; set; }
[UIHint("Time")]
public DateTime TimeProperty { get; set; }
The UIHint attribute name has to match the file name of your template, and UIHint is in System.ComponentModel.DataAnnotations, so you will need the appropriate using statement/assembly reference if you don't have it already.
Alternatively, use a TimeSpan to represent your times - that is what DateTime returns for its TimeOfDay property...

Related

kendo MVC wrapper grid. How do i specify the data type of a nested model field?

I have a project work work with hundreds of grids. On one grid in particular, the original designer created a view and added it as a nested model inside our driver model. This is a problem because Kendo seems to not be able to detect the field type of a field nested this way. When it can't, it assumes the field is a string.
In my particular case, I have two fields that contain dates that we want to filter on, but the date filtering is broken because of this.
I was able to find numerous examples of specifying it in the data source, but only for jquery grids (one example: https://docs.telerik.com/kendo-ui/knowledge-base/use-nested-model-properties ). I can't convert this to mvc because the methods aren't lining up.
Any idea on how to do this in mvc? Note: I also tried just changing the UI on the filter to date and that didn't work either. I got a stack trace claiming date needed to be a string.
As far as I understand the model passed to the Grid's field is structured like this:
public class OrderViewModel
{
public int OrderID
{
get;
set;
}
public CityModel ShipCity
{
get;
set;
}
}
public class CityModel
{
public int CityID
{
get;
set;
};
public string CityName
{
get;
set;
};
}
Then you can utilize the ClientTemplate configuration to get the CityName to populate the column:
columns.Bound(p => p.ShipCity).ClientTemplate("#=ShipCity.CityName#");
For more information refer to the Kendo UI Templates article
or
this forum answer that shows how to set a default to a nested field in a Grid's DataSource Model configuration.
Unfortunately, according to Telerik , the fact is that you simply can't do what I was trying to do. The solution is to flatten the model. I pulled the questionable fields into notmapped fields in the master model.
The relevant part of their response:
In MVC the nested properties are properties to another Model. As the Telerik UI Grid needs a flat structure of data, the nested properties could be shown with the help of a ClientTemplate, but they will always be string typed.
In order to achieve the desired behavior, I would recommend making the pointed Date fields - part of the Main Model and using them as flat data out of the box.
Link: https://www.telerik.com/forums/kendo-mvc-wrapper-grid-how-do-i-specify-the-data-type-of-a-nested-model-field
The caveat here is you can't filter a linq-for-queries datasource to a notmapped field because it doesn't exist in it but in my case, a .toList() didn't cause any performance problems because the dataset was small, with only a few hundred records.
However, you can edit the incoming DatasourceRequest object to modify the filters and sorts to point at the sub model, after your controller read is hit.

ASP.NET MVC 4 avoid generation of data-val-date for datetime

how can I avoid the generation of the html attribute "data-val-date" for the element created from a Datetime property?
The model:
public class RegisterModel
{
[Required]
[Display(Name = "Date of birth")]
public DateTime? DateOfBirth { get; set; }
}
The view:
#Html.LabelFor(m => m.DateOfBirth)
#Html.EditorFor(m => m.DateOfBirth)
In fact, I'm creating a three drop down lists element for selecting the date of birth, which don't give a value in a date format.
Some solutions I've seen, consisted in a work around: removing the validation with a javascript.
The solution I envisage is to split the DateTime property into three long one for each value (day, month, year).
Ok, this took me an afternoon of work... apparently mvc4 decided that it was time to render a data-val-date="Message" on EVERY datetime property on the viewmodel. I've tried to modify this default behaviour but didn't succeed.
This solved my problems:
$.validator.addMethod('date',
function (value, element) {
return true; // since MVC4 data-val-date is put on EVERY vm date property. Default implementation does not allow for multiple cultures...
});
You can also try to write your own editor template named "DateTime.cshtml" in your shared EditorFor folder, but don't use TextBoxFor there, because that one is polluted as well.
data-val-date is used by the validation system to validate the date. If you remove it, client-side validation won't work.
If that's what you want, then just disable client-side validation.
Add this to your application start in your global.asax file and the form should fire.
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

Automatical bind of datetime fields in MVC3

I have a page with many date fields, which can be dynamically added on client side. I have a DatTime? property on editor template for this field:
[Display(Name = "Bar Admission Date")]
public DateTime? AdmissionDate { get; set; }
When I'm submitting a form I get a null data in AdmissionDate field because binder doesn't know the format of the field.
I have 2 ideas of how t oovercome this issue:
Make a string field in model and parse it on a server side. Simple and pretty quick.
Write a custom model binder for date fields. I don't like this solution because I don't know the keys for all fields that I will use.
Is there better solution? I searched how can I overload TextboxFor method in order to pass it a culture, but I didn't find
Sounds like you should use an enumerable (IList/ICollection) of DateTime?. Phil Haacked has a good article on model binding to a list (even when the number of items is dynamic).
Updated
As for the formatting problem, I would look at how to set the culture for the project/model binder.

Problems with DateTime, it appears with 00:00:00

I have my database which has a DateTime type for Birthdate value when I register the user.
When I receive my data back, to edit the register form, I have my Razor like this:
#Html.TextBoxFor(model => model.Birthdate)
The date shows like this: 28/05/1983 00:00:00
I want only the birthdate, obviously. In my Controller, I have this:
User userset = db.User.Find(id);
return View(userset);
Very simple... Could anyone help me to solve that?
Set the DisplayFormat data annotation above the property in your model.
public class User
{
[DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
public DateTime Birthdate { get; set; }
...
}
Then instead of using #Html.TextBoxFor(..) use #Html.EditorFor(...).
See the DisplayFormatAttribute MSDN page for more details.
If you have generated your data model using EF you can simply create a meta class for your class to apply data annotations. For example, if my db file is called MyDB.edmx, create a buddy class file called MyDB.cs. Then inside there, I would extend the User class by attaching a metadata class to it and specifying the data annotation in the metaclass:
[MetadataType(typeof(UserMetaData))]
public partial class User{ }
public class UserMetaData
{
[DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
public DateTime Birthdate { get; set; }
}
See Scott Gu's post on validation, mainly the section 'But what if we are using a graphical tool for our ORM mappings?'.
You can do something like this using Html.TextBox instead of using Html.TextBoxFor.
#Html.TextBox("Birth date", String.Format("{0:dd/MM/yyyy}", Model.Birthdate))
DatePicker from jQuery is a better approach to receive date input from user. It is particularly helpful to avoid various date format confusion.
More details on: http://blogs.msdn.com/b/stuartleeks/archive/2011/01/25/asp-net-mvc-3-integrating-with-the-jquery-ui-date-picker-and-adding-a-jquery-validate-date-range-validator.aspx

Reusable editor template with DropDownList for business objects

I'm using MVC3 with Razor views and would like to build reusable DropDownLists for several of my classes, but after much searching I have not found an example that performs exactly how I need it...
For this example I have two classes like this:-
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public Group Group { get; set; }
}
public class Group
{
public int ID { get; set; }
public string Name { get; set; }
}
I have a working Controller/View for Person. The view has a DropDownListFor control:
#model Person
...
#Html.DropDownListFor(o => o.Group.ID, (ViewData["groups"] as SelectList))
The view uses the Person class directly, not an intermediary model, as I haven't found a compelling reason to abstract one from the other at this stage.
The above works fine... in the controller I grab the value from Group.ID in the Person returned from the view, look it up, and set Person.Group to the result. Works, but not ideal.
I've found a binder here: MVC DropDownList values posted to model aren't bound that will work this out for me, but I haven't got that working yet... as it only really seems useful if I can reuse.
What I'd like to do is have something like this in a template:-
#model Group
#Html.DropDownListFor(o => o.Group.ID, (ViewData["groups"] as SelectList))
And use it in a view like this:-
#Html.EditorFor(o => o.Group)
However the above doesn't seem to work... the above EditorFor line inserts editors for the whole class (e.g. a textbox for Group.Description as well)... instead of inserting a DropDownList with my groups listed
I have the above template in a file called Group.cshtml under Views/Shared/EditorTemplates
If this worked, then whenever a class has a property of type Group, this DropDownList editor would be used by default (or at least if specified by some attribute)
Thanks in advance for any advice provided...
You can create a drop down list user control to handle this. Under your Shared folder create a folder called EditorTemplates and place your user control there. MVC, by convention, looks in the Shared/EditorTemplates for any editor templates. You can override where it looks for the editor templates but I won't go in to that here.
Once you have your user control created, you'll need to decorate the appropriate property with the "UIHint" attribute to tell the engine what editor it should use for that property.
Following would be a sample implementation.
In the Shared/EditorTemplates folder your user control (_GroupsDropDown.cshtml in this case) would look like:
#model Group
#Html.DropDownListFor(o => o.ID, (ViewData["groups"] as SelectList))
Modify the Group property in the Person to add the UIHint attribute as follows:
**[UIHint("_GroupsDropDown")]**
public Group Group { get; set; }
In your controller you would need
ViewData["groups"] = new SelectList(<YourGroupList>, "ID", "Name");
Once you have the above code you can use the EditorFor syntax like you desire.
Hope this helps.

Resources