How do you access the model in an ASP.NET MVC Editor Template? For example if the parent view contains say:
#Html.EditorFor(x => x.Surname)
Then inside Views/Shared/EditorTemplates/String.cshtml we have:
#model String
<div class="field">
#Html.LabelFor(x => x)
#Html.TextBoxFor(x => x)
#Model.Length
</div>
This fails at #Model.Length because Model is null, although the LabelFor and TextBoxFor render the correct Surname properties.
When Html.DisplayFor with the equivalent template file is used, Model does contain the given string value.
Creating a Editor Template for something as broad as String could have unintended consequences, since you will very likely have many EditorFor(x => x.StringValue)s in your code that you don't want this Editor Template to apply to.
It's likely that you have another EditorFor that is causing the nullref exception here.
Related
I have a project which contains a simple form for collecting signup info. Recently I have been working to add localization to the project, as all of the text shown to the user was hardcoded. I'm not sure what changed, but for some reason, now when Razor renders an HTML element using the Html.EditorFor method that ends up being a textbox, the Name property of the element has ".textbox" appended to it.
This breaks the bindings, so that when I receive my model all of the text values are null. Here is an example of what I'm seeing, Razor code:
<div class="form-group" ng-class="{ 'has-error': validate && accountForm.FirstName.$invalid }">
#Html.LabelFor(m => m.FirstName, new { #class = #ViewBag.LabelCssRequired })
<div class="#ViewBag.TextboxCss">
#Html.EditorFor(m => m.FirstName, new { htmlAttributes = new { ng_model = "firstName" } })
</div>
</div>
and here is the rendered output:
<input class="text-box single-line form-control ng-valid-maxlength ng-not-empty ng-dirty ng-valid-parse ng-valid ng-valid-required ng-touched" id="FirstName_textbox" maxlength="100" name="FirstName.textbox" ng-model="firstName" required="required" type="text" value="">
It is also adding a "_textbox" to the id, but I'm not as concerned about that at the moment. For some reason, this only seems to be happening to input elements where the type is "text". I have another input generated with.EditorFor which has the type of email and it doesn't have any modifications to the name.
This behavior also seems to be restricted to Html.EditorFor, if I use.TextboxFor, it works fine.
I have been able to make the bindings work by explicitly setting the #Name property in Razor, but this only masks the symptom, and I would like to avoid having to do this for every text input on the site.
Has anyone seen this behavior before, or know of a fix?
By default, the TextBoxFor helper generates HTML using a built-in template. You can override the defaults by creating files in the project root\views\shared\editortemplates folder.
Therefore the problem can be caused by some custom template being present there. Normally, you need to check for files whose name Match either the datatype (such as string) or the control type (such as TextArea). If the corresponding model property has a UIHint attribute on it, a custom file specified in it can also come into play.
This question already has answers here:
ASP.NET MVC 3 Model Id using Route Id value
(3 answers)
Closed 6 years ago.
I'm creating a strongly-typed partial view for a form in ASP.NET mvc, in which I want to use a hidden input to convey the Id property of the particular view model. The controller that renders the view accepts an id parameter, registered as an option url parameter in my RouteConfig.cs, which is meant to be unrelated.
If the controller is passed a username of "Tim" as a routing paramter, and the model that is passed to the partial view has an Id of "e1ac2e44-1e09-4bb4-a7f0-85e1eedf3448" then here is what happens:
#Html.DisplayFor(m => m.Id) correctly displays e1ac2e44-1e09-4bb4-a7f0-85e1eedf3448 as I want it to.
#Html.HiddenFor(m => m.Id) incorrectly creates a hidden input with a value of "Tim":
<input id="Id" name="Id" type="hidden" value="Tim">
The same happens for:
#Html.HiddenFor(m => Model.Id)
#Html.HiddenFor(m => m.Id, new { value = Model.Id })
#Html.HiddenFor(m => m.Id, new { value = "Obvious eye-catching string" })
#Html.Hidden("Id", Model.Id)
#Html.Hidden("Id", "Obvious string")
However, #Html.Hidden("NotId", Model.Id) creates a hidden input with the correct value, but not with a name matching the intended property in my view model:
<input id="NotId" name="NotId" type="hidden" value="e1ac2e44-1e09-4bb4-a7f0-85e1eedf3448">
With further toying around , I've found that TextBoxFor, TextAreaFor and EditorFor all bind in the same way as HiddenFor and show up displaying "Tim", not the alphanumeric user ID. This leaves me with two basic questions:
Why does #Html.DisplayFor bind differently from other Razor helpers?
What is the correct way / easiest work-around to use my view model's property Id and not the route parameter id apart from changing names?
Posting comment with elaboration here..
HiddenFor along with EditorFor are (extension) methods that are used to indicate that the value will be needed to be passed back back with the form. Thus it makes sense that they would look for a specific override from the user on that RouteValue (here you over wrote Id). DisplayFor is the method used just to display the value without it being passed back when the form is submitted. Here since you don't wan't to pass back the current value of Model.Id you should use #Html.DisplayFor(m=> m.Id,new {Hidden})
Inside razor view I used model for rendering label like
#Html.LabelFor(model => model.MyName, htmlAttributes: new { #class = "control-label col-md-6" })
and now I want to use it's value instead of data annotation attr. value so I tried with DisplayFor like
#Html.DisplayFor(model => model.MyName, new { #class = "control-label col-md-6" })
this css class control-label col-md-6 is not apply.
Why?
The difference is that #Html.LabelFor helper function renders a <label></label> tag, and the #Html.DisplayFor helper function does not render any html tag, instead it renders plain text. For example the following code:
#Html.DisplayFor(model => model.MyName, new { #class = "control-label col-md-6" })
returns raw text:
Martin
considering that MyName had the value "Martin". And the code:
#Html.LabelFor(model => model.MyName, htmlAttributes: new { #class = "control-label col-md-6" })
will return:
<label class="control-label col-md-6">Martin</label>
Consider the difference.
Use following (if you want to use #Html.DisplayFor):
<span class"control-label col-md-6">#Html.DisplayFor(model => model.MyName)</span>
DisplayFor doesn't work like the other *For helpers. Like EditorFor, it's what's referred to as a "templated helper". In other words, what it renders is controlled by a template that can be modified. Importantly, for both of these methods, if you look up their documentation in MSDN, you'll see that the parameter that would normal correspond to htmlAttributes with the other helpers, instead refers to additionalViewData with these two. This is because, again, their output is controlled by essentially views, which take ViewData.
Additionally, with DisplayFor in particular, the default templates pretty much just output the value, with no HTML. If you pass a string property, for example, the output will be the value of that string and nothing else. Therefore, there's nothing to tie the HTML attributes to, even if you could pass them in.
If you want to do what you're trying to do, you'd have to create custom display templates. This can be done by adding views named after types (e.g. String, Boolean, Byte etc.) or members of the DataType enum (CreditCard, EmailAddress etc.), to Views\Shared\DisplayTemplates. For example, if you created a view at Views\Shared\DisplayTemplates\String.cshtml, then when you called DisplayFor with a property of type string, that view would be utilized to render it. You could then wrap the value that would otherwise be just output directly in some HTML of your choice and utilize ViewData to apply the appropriate HTML attributes. For example:
<span class="#ViewData["class"]">#ViewData.TemplateInfo.FormattedModelValue</span>
.NET Core 2.2 Razor Pages Resize Checkboxes
Late to the game here but needed to make check-boxes huge compared to how Razor Template displays them. Because I wanted user to see if it was checked or not.
I tried above stuff, didn't work. So I used Chrome Developer Tool to look at what the page was rendering and it showed this for the checkbox:
input[type="radio"], input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
And I was going to go find it in the CSS file because I could use all check-boxes to be bigger. However, it said it was located here:
reboot.scss:373
Now, I swear it referenced a different scss file when I first opened in developer. But since it looked like Greek to me, a code slob, I just decided to put this (after trying it in style above) at the top of my Razor Page. Notice I just cloned the hidden style above and just added width and height:
<style>
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
width: 40px;
height:40px;
}
</style>
Now, Here is the Razor control I was displaying. It ends up as a checkbox in html at end, but I believe Razor Page is smart enough to know it was a True/False field and showed it as a text box. But. . . not before it applied the sizing I added!! Hope this helps someone.
<td>
#Html.DisplayFor(modelItem => item.Moderated)
</td>
I am using the following code to display text from my view model in my view:
#Html.DisplayFor(m => m.Name)
When I look at the HTML details in IE9 (which I have to use at work) there is no class associated with the name, it just uses the Body CSS styling instead of the display-field class styling. Does anyone know what might be causing this issue or how I might edit the CSS for the text created?
if it is a label, use proper helper for it as Nataka526 suggests
otherwise put it in a span with a class and update css for that class:
your html:
<span class="name">
#Html.DisplayFor(m => m.Name)
</span>
your css:
.name {
//custom css
}
UPDATE
Another option:
Update your Display Templates to handle a specific ViewData key:
in Views > Shared > DisplayTemplate (create this folder if you don't have it already):
add file String.cshtml:
#model string
#{
string myClass = ViewData["class"]
}
#if(string.IsNullOrEmpty(myClass))
{
#:#Model
}
else
{
<span class="#myClass">#Model</span>
}
you may need to add DisplayTemplates for other tipes as well besides string.
In the view you will write something like this:
#Html.DisplayFor(m => m.Name, new { #class= "name" })
This will add spans around it automatically.
UPDATE
Explanation:
There is an overload on Html.DisplayFor which accepts two parameters: expression and object additionalViewData. So the second parameter that I pass is that anonymous object additionalViewData. I create this object with property called class
Inside of the html helper I then check if there is a ViewData with a key class and if there is, I put output inside a span with that class value.
**
updated variable name from class to myClass since "class" is not appropriate variable name.
DisplayFor is used for templating reasons. If you aren't using a template, then you should just use the item like so: #Model.Name If you want to give it a class or id, then you need to wrap it in a span or div.
Your problem is that you're using the wrong method to output data, and expecting it to do something else. There is no built-in way to output raw data with class names.
So your choices are, wrap the raw item in a container that you can apply the css to, or create a template to use for these, then specify the template name in the DisplayFor like so:
#Html.DisplayFor(m => m.Name, "NameTemplate")
I have a single page with a Partial control on it called PartialContact
In reusing this control I would like to change the title within the PartialContact control. i.e.
// change to Title1
#Html.EditorFor(model => Model.Contact1, "PartialContact")
// change to Title2
#Html.EditorFor(model => Model.Contact2, "PartialContact")
// change to Title3
#Html.EditorFor(model => Model.Contact3, "PartialContact")
Whats the best way to pass in title text within Razor? TempData?
(I have multiple different controls I need to do this with aswell)
Many thanks
Chris
Use the ViewDataDictionary to pass the value, e.g.
#{
ViewData["Title"] = "Blah";
Html.EditorFor(model => Model.Contact1, "PartialControl", ViewData);
}
Then access it in the partial with #ViewData["Title"]