How to display the array index number in an editor template - asp.net-mvc

In my model I have a List property of a complex type called EventField.
I created an editor template, which works fine using:
#Html.EditorFor(e => e.EventField)
My question is, within that Editor template I want to pick out the index/sequence number on its own, as a number. This index will simply be added into the template as a data attribute so I can pick it up using javascript.
A couple of answer are out there that don't suffice:
#html.IdFor - outputs the whole name e.g Name[0].other
here - you can't pass through the model name "EventField" this way.
Is there a simple method/function/helper that will give me access to that Index, without having to change how I call the Editor template?

How about:
#using System
#using System.Text.RegularExpressions
var i = Convert.ToInt32(Regex.Matches(
ViewData.TemplateInfo.HtmlFieldPrefix,
#"\[([0-9]+)?\]")[0].Groups[1].ToString());

Related

How to show the value of model in Kendo Custom Editor Template?

I'm using a scheduler of Kendo UI for MVC. I created a Custom Editor Template. It works fine. When click the schedule, it pops a windows and show the info.
I added some properties in the model, the value passed to the editor template. Now, the question is:
How can I show the added properties (just as value, and I do not want to change it) in the editor template popup?
I found that if I use a textbox:
#(Html.TextBoxFor(model => model.Role, new { #class = "k-textbox" }))
It shows a textbox and shows the correct value of Role. However, if I use
<div>#(Model.Role)</div>
It shows blank, just as the value is NULL.
I actually want to show several added properties as a sentence, i.e. I added Role and UserName and I ant to show something like:
UserNameValue has Role of RoleValue
Anyone knows how to do it?
I use this as sample in the code:
http://www.telerik.com/support/code-library/custom-editor
Thanks
Your solution is to put this line because the editor template is binded by mvvm
<div data-bind="text: Role"></div>
Docs
In the code: model => model.Role model is just an alias, not an actual object. You could replace it with m => m.Role and it would function the same.
When you write #Model in your view you are using the object of ContractViewModel which is passed from Controller action, if it is not passed from View it can be null and accessing any property of Model can throw Null Reference Exception and writing Model.Contractors you basically mean ContractViewModel.Contractors
See this post: mvc uppercase Model vs lowercase model

In a custom editor template, how do I access the field name I should use for the edit control? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to get model's field name in custom editor template
When outputting an edit control for a special type of entity, for example, let’s say a color or something:
#Html.EditorFor(product => product.Color)
I want this to output a drop-down list, so I tried to create a custom editor template that shall render such a drop-down. Here is what my template looks like so far:
#model MyProject.Models.Color
#using (var db = new MyProject.Models.DbContext())
{
#Html.DropDownList(???,
new SelectList(db.Colors, "Id", "Name", Model))
}
What do I have to put instead of the ??? — the parameter that specifies the HTML name attribute for the drop-down?
(For obvious reasons, it’s not just "Color". Consider several invocations of the same edit template for different fields of the same type, e.g.:
#Html.EditorFor(product => product.InnerColor)
#Html.EditorFor(product => product.OuterColor)
Clearly, this needs to generate drop-downs with different names.)
The drop-down list already receives the correct field name all by itself. Anything you pass into the name parameter gets concatenated onto the field name, preventing it from being recognised.
The correct solution is to pass the empty string:
#Html.DropDownList("", new SelectList(...))
An answer to this question suggests to use
ViewData.TemplateInfo.HtmlFieldPrefix
So the full code will be somthing like
#model MyProject.Models.Color
#using (var db = new MyProject.Models.DbContext())
{
#Html.DropDownList(ViewData.TemplateInfo.HtmlFieldPrefix + "_Color",
new SelectList(db.Colors, "Id", "Name", Model))
}

In an Editor Template call another Editor Template with the same Model

I have an editor template and within that editor template i want to call another editor template with the same model (i.e. nested), but it does not seem to display.
ie. \EditorTemplates\Template1.cshtml
#model foo
// insert code here to edit the default fields.
// display extra fields via another editor template.
#Html.EditorForModel("Template2") // or #Html.EditorFor(m => m, "Template2")
and \EditorTemplates\Template2.cshtml
#model foo
#Html.TextBoxFor(m => m.Name)
I am sure someone will question why? Well, the nested template will only be displayed if a condition is met (ie. #if (#Model.IsConditionMet) { .... } ), but I have left that out of my prototype for simplicity.
Short answer:
Use Html.Partial instead.
So, in your Template1.cshtml file:
#model foo
// insert code here to edit the default fields.
// display extra fields via another editor template.
#Html.Partial("EditorTemplates/Template2", Model)
Long answer:
This sadly appears to be by-design. MVC tracks the models that have been rendered, and if your model has already been rendered by a template, it won't do it twice, even if the template is different. Hence why the second #Html.EditorForModel("Template2") just does nothing.
Specifically, it's tracked in ViewData.TemplateInfo.VisitedObjects, which is an internal field, so there's no hope in you modifying it after the fact. The intention of this field is to prevent infinite recursion. Noble, but annoying in that it doesn't take the template used into account.
I found this out by looking at the source code, which is great for finding these weird idiosyncrasies of MVC.

Is there a way to choose what DisplayFor renders?

Consider this code:
<%: Html.DisplayFor(model => model.SomeBoolean)%>
<%: Html.DisplayFor(model => model.SomeInt)%>
First one is bound to a boolean this will render a disabled drop down list.
The second is bound to an int and this will simply render the result as text.
I would like the int to also render a drop down list too.
What are my options?
Many thanks.
MVC has a set of default editor and display templates. You can create your own by creating a DisplayTemplates folder in either the view folder for the controller, or you can define a more global template by putting it in a DisplayTemplates folder in the Shared folder.
For system types, use the actual type name and not the language specific shortcut (i.e. for int, call the template Int32.ascx or Int32.cshtml for Razor.
You can further specify templates by either using an overload (I know this is possible for EditorFor, I'm guessing it is for DisplayFor as well), or if you have a specific property that you want to use a different template for, you can use data annotations.
This same technique works for complex types as well.

How do I bind to a specific array element in ASP.NET MVC?

I'm using ASP.NET MVC RC1 and trying to bind a textbox to an object property like so:
<%= Html.TextBox("Comments.Contacts[0].ContactName") %>
It seems like it should work, since this does:
<%= ((MuralProject)ViewData.Model).Comments.Contacts[0].ContactName %>
But alas, the result in the textbox is an empty string. Am I doing something wrong?
The first argument for the text box extension method sets the name of the input element that's eventually created and also tries to get an entry from ViewData/Model (for the model it uses TypeDescriptors / reflection) based on that argument.
The way it does this is just by splitting up the input string at the dots then checking the ViewDataDictionary for specific keys and the Model via reflection so in the case you give it'll try and look for Contacts[0] rather than Contacts and won't pick up your property.
To get around this you just need to supply the actual value of the object e.g.
Html.TextBox("Comments.Contacts[0].ContactName",
Model.Comments.Contacts[0].ContactName)
You can see this yourself if you look at the MVC source and take a peek at the ViewDataDictionary class.

Resources