I have a question about the IntegerTextBoxFor from Telerik Extensions for MVC. I'm currently trying to remove the use of commas from it. Currently here is what I have.
Editor Template called Int32.cshtml
#model System.Int32
#using Telerik.Web.Mvc.UI
#Html.Telerik().IntegerTextBoxFor(model => model)
Model
[NopResourceDisplayName("Admin.ReturnRequest.List.SearchOrderId")]
public int SearchOrderId { get; set; }
I have tried adding [DisplayFormat(DataFormatString="{0:g}")] to the model but it has done nothing. I also tried using 0:#####, 0:00000, and 0:n.
You can configure the group separator with calling the NumberGroupSeparator method on the IntegerTextBoxFor(model => model).
So if you don't need the separator you can set it to the empty string:
#Html.Telerik().IntegerTextBoxFor(model => model).NumberGroupSeparator("")
Telerik don't have this "NumberGroupSeparator" method on Kendo UI.
#(Html.Kendo().IntegerTextBoxFor(model => model)
Related
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;
When using Razor to render a form for a complex Model that has sub-models, we'd usually use Partial Views to render the sub-models.
Simple example Model:
public class BlogPost
{
public string Content { get; set; }
public List<Comment> Comments { get; set; }
}
public class Comment
{
public string Content { get; set; }
}
BlogPost.cshtml:
#model BlogPost
#Html.TextAreaFor(x => x.Content)
#for (int i = 0; i < Model.Comments.Count; i++)
{
#Html.Partial('Comment', Model.Comments[i])
}
Comment.cshtml:
#model Comment
#Html.TextAreaFor(x => x.Content)
Now for the issue:
Say we want to send the values of all fields to a controller action that takes BlogPost as a parameter. The fields are going to be posted back to the controller like so:
Content=The+content+of+the+BlogPost&Content=The+first+Comment&Content=The+second+Comment
But what we need to have MVC map them correctly to the BlogPost view model, we need this naming convention:
Content=The+content+of+the+BlogPost&Comments[0].Content=The+first+Comment&Comments[1].Content=The+second+Comment
How can this be achieved in a clean way? We can only think of two ways which both seem to compromise the design:
Either we pass the BlogPost as a model to the partial view such that we can define the text area like so: #Html.TextAreaFor(x => x.Comments[i].Content). But this means we couple the partial view for comments to the parent view model - you could think of a scenario where the same partial view should be used in a different context, which is not possible if the partial view depends on the parent view model. Futhermore, the i would have to be passed to the partial view somehow.
Or we fall back to explicitely defining the name of every single field with strings: #Html.TextArea(ViewBag.Prefix + ".Content").
Is there any way to tell the partial view to apply a certain prefix to all field names?
chiccodoro,
if you create and EditorFor template of type Comment, mvc will handle all of this beautifully for you. However, that will only work well in a scenario where the rows are already present in the DB. Exampel from SO:
Submiting Parent & Children in razor
If you need to create new rows on the fly, then you'll have to use a little bit of trickery to allow the fields to operate as required. I used an article from steven sandersons website which allows you to add collection items at runtime and still retains unobtrusive validation etc. see this SO question and related article ref:
Editing a Variable Length List, ASP.NET MVC 3 Style with Table
I have just registered, and this is my first post, so please bear with me if the question is not the best. I have had a look about and can't find an answer that suits my requirements; this is possibly because it's not possible to achieve what I want.
I have a partial view which pulls through an IEnumerable list of EditorFor fields from a viewmodel:
#model DocumentViewModelContainer
#Html.EditorFor(m => m.Document.Metadata)
The DocumentViewModelContainer has the following code:
public class DocumentViewModelContainer
{
public DocumentViewModel Document
{
get;
set;
}
The DocumentViewModel has the following code:
public class DocumentViewModel
{
public IEnumerable<DocumentMetadataFieldViewModel> Metadata
{
get;
set;
}
}
There's a ton of other objects in both view models that I've left out as being irrelevant in this question. The DocumentMetadataFieldViewModel is made up of several fields of standard types (int, strings etc.)
What I'm trying to achieve is adding an OrderBy to this list pulled back by ordering by an object in the bottom view model, such as follows:
#model DocumentViewModelContainer
#Html.EditorFor(m => m.Document.Metadata.OrderBy(i => i.InstanceFieldOrder))
However this gives the error:
System.InvalidOperationException : Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
I'm not only very new to MVC, but to C# in general; this project has had me learning the language on the fly, so please play nice :)
Thanks,
Mark
You should do this ordering in your controller action which is responsible to retrieve your view models and pass them to the view.
You could always perform the following horror in your view:
#model DocumentViewModelContainer
#{
Model.Document.Metadata = Document.Metadata.OrderBy(i => i.InstanceFieldOrder).ToList();
}
#Html.EditorFor(m => m.Document.Metadata)
but promise me you won't do that.
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.
I am using MVC3 razor. I have a scenario where I have to use a partial view multiple times on the same parent view. The problem I am having is that when the Parent View gets rendered, it generates same names and ids of the input controls within those partial views. Since my partial views are binded to different models, when the view is posted back on "Save" it crashes. Any idea how can i make the control id/names unique, probably some how prefix them ?
Awaiting
Nabeel
Personally I prefer using editor templates, as they take care of this. For example you could have the following view model:
public class MyViewModel
{
public ChildViewModel Child1 { get; set; }
public ChildViewModel Child2 { get; set; }
}
public class ChildViewModel
{
public string Foo { get; set; }
}
and the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Child1 = new ChildViewModel(),
Child2 = new ChildViewModel(),
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
and inside the Index.cshtml view:
#model MyViewModel
#using (Html.BeginForm())
{
<h3>Child1</h3>
#Html.EditorFor(x => x.Child1)
<h3>Child2</h3>
#Html.EditorFor(x => x.Child2)
<input type="submit" value="OK" />
}
and the last part is the editor template (~/Views/Home/EditorTemplates/ChildViewModel.cshtml):
#model ChildViewModel
#Html.LabelFor(x => x.Foo)
#Html.EditorFor(x => x.Foo)
Using the EditorFor you can include the template for different properties of your main view model and correct names/ids will be generated. In addition to this you will get your view model properly populated in the POST action.
There is an alternative:
Add a prefix to the PartialView
Bind the model, removing the prefix
For 1, set the prefix in your View:
ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = "prefix";
For 2, you can recover the data with UpdateModel, like this:
UpdateModel(producto, "prefix");
This is not very advisable because your action doesn't receive the data as a parameter, but updates the model later. This has several inconvenients: 1) it's not clear what your action needs by looking at its signature 2) it's not easy to provide the input to the action for unit testing it 3) the action is vulnerable to overflow parameters (parameters provided by the user that shouldn't be there and are mapped to the model).
However, for 2 there is an alternative: register a custom Model Binder that allows you to do remove the prefix. And the custom Model Binder must know about it.
A good solution is in this SO Q&A: How to handle MVC model binding prefix with same form repeated for each row of a collection? But it has a little flaw: if you add a hidden field with the name "__prefix" in a partial view, and you render it several times as a partial view, this ID will be repeated for several different elements in the page, which is not allowed, and can provoke some trouble. And one of the most important reasons to provide a prefix is precisely rendering the same "edit" view as partial views for several instances of an entity. I.e. this would happen in a page like gmail, where you can edit several emails at once.
There are several possible solutions for this problem.
One of them is providing the prefix as a query string or routedata value, and not as a form field, which avoid the Id conflicts, and can be found by the model binder. (It can always have the same name).
Another solution is to use a hidden field, with a fixed pattern, but which is different for every rendered view. The prefix could follow this pattern for uniqueness: "PP$ActionControllerId" like "PP$EditProduct23", which is unique for each rendered view, and can be easily found between the request parameters looking for one that starts with "PP$".
And a final solution would be to create the prefix only in the view, and not providing it in any kind of request parameter. The Model binder would have to look for the prefix examining the names of the request parameters, until it finds one whose prefix follow the pattern.
Of course, the custom ModelBinder must be adapted to work tieh the chosen convention.