Applying css class using Html.DisplayFor inside razor view - c#

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>

Related

Html.EditorFor adding .textbox to element name

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.

How do you access the model in an EditorFor template?

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.

Creating a new object in a view which passes IEnumerable object

I'm having a bit of pain trying to solve how can I create a new object when I'm passing to my view a IEnumerable.I'm having the creation of the new item in a modal jquery-ui window on the same page.
<div class="form-group">
#Html.LabelFor(model => model.Title)
<div class="col-md-10">
#Html.EditorFor( model =>model.Title)
#Html.ValidationMessageFor(model => model.Title, "Please choose a title that is not empty or less than 3 symbols")
</div>
</div>
So this is the code snippet that I'm trying to implement in the main view from where my js gets the information,but since my model is a collection I cannot access the editor options in my razor view.
This is a part of my js file where I get the values of the items inside the input boxes listed above which do NOT work becase I'm operating on a collection.I cannot change the model so I need a shortcut through it.
$.ajax({
url: "/Course/Create/",
type: "POST",
data:{
Title: $("#itemTitle").val(),
CourseDescription: $("#itemDescription").val(),
CourseCategory: $("#itemCategory").val()
},
You should pass a View Model that will contain both the IEnumerable collection + an object that you would like to submit (with Title, Description and Category properties).
In case you cannot change the model that you are passing to the view you should not use Html.EditorFor but simply Html.Editor (the same applies to Html.LabelFor and other Html extensions that you use there).
Of course you then need to pass appropriate name parameter ( e.g. "itemTitle") to these extensions that will comply with the ones used in the JS code.

adding a class to EditorFor - razor c#

(The editor is for a DateTime property called "ADate"
I am trying this but it does not work.
#Html.EditorFor(model => model.ADate, new { cssClass = "date" } )
So I tried this:
#Html.TextBoxFor(model => model.ADate, new { #class = "date" })
but it outputs type = text.. ofcourse it does.
So I tried a template... I added a folder in shared:
Shared/EditorTemplates
and then I created a .cshtml partial view called Date.cshtml
Now what on earth do I put inside it :O...
I have tried to understand lots of posts and stack overflow entries but it's not sinking in.
The goal is to attach a datepicker to the class ".date" across the entire app where ".date" class is used... The TextBoxFor works with my adding class part... but as I said, the type changes from date to text :(
Ok so this is what you can do:
In your EditorTemplates folder create a template called DateTime.cshml (the name will resolve automatically if you use it for dates, otherwise you have to specify it when using it).
Then in it:
#model System.DateTime
#Html.TextBox(
string.Empty,
Model.ToString("yyyy-MM-dd"),
new { #class="datepicker", #type = "date"})
Using the last parameter you can specify any html attribute (class, data, type etc.).
Then you use it like this:
#Html.EditorFor(x => x.ADate)
In case you chose to name your template with a different name you can specify it by invoking another overload:
#Html.EditorFor(x => x.ADate, "MyOtherAwesomeTemplate")
The EditorFor html helper does not render a date picker for your DateTime attributes (if that's what you want to do). The default EditorFor for DateTime is a text input. If you want to use a date picker, you'll have to use jQuery DatePicker (or any other third party date picker).
Also, the EditorFor helper does not have a parameter for html attributes. If you want to assign a class, you'll have to use TextBoxFor.
In your main View, use the EditorFor like this:
#Html.EditorFor(model => model.ADate)
Then, in your Editor Template (Date.cshtml), you'll have:
#model System.DateTime
<script type="text/javascript">
$(function () {
$(".date").datepicker();
});
</script>
#Html.TextBox("", Model.ToString("d"), new { #class = "date" })
You can download the jQuery UI from here: Download jQuery UI
And, you can learn more about the jQuery DatePicker here: jQuery DatePicker
You can do this
#Html.EditorFor(model => model.ADate)
<style type="text/css">
#ADate
{
#* your css properties goes here *#
}
</style>
this works fine for MVC3 Razor

MVC: Dynamically create new element from template

I have an MVC app. Some elements are rather complex, so I created a template for them.
I use them calling #Html.EditorFor(). The problem is that I need a possibility to create such elements dynamically, I mean after clicking on a button 'Create New' I want to generate an empty template and let user to fill it. I can use mustache template engine or smth like this, but in this case I need to duplicate my html - in razor template and in html. I don't want to repeat myself, what is the best way to achieve this?
Another problem is that when I generate view for IEnumerable<> - razor created proper names for elements with proper indexes. In a case I want to create new element - how should I set these indexes to let binder properly work on POST? Is there is a better solution than using jQuery for this?
Thanx in advance.
UPDATE:
Here is an editor template:
#model FakeViewModel
<li>
<div>
<h3><span>#Model.Title</span><span class="icon-remove"></span><span class="icon-move"></span></h3>
<div>
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(mp => mp.Category)
<div>
<span class="font-small">Title</span>
</div>
<div>#Html.TextBoxFor(m => m.Title, new { #maxlength = FakeViewModel.MaxTitleLength, #class = "title-textbox" })</div>
<div>
#Html.TextAreaFor(m => m.Description, new { #placeholder = "short description", #data_max_length = "90" })
</div>
</div>
</div>
</li>
This is how I render it, "Special" is a type of IEnumerable<FakeViewModel>
<ul class="container" id="special">
#Html.EditorFor(m => m.Special)
</ul>
So, after rendering this I have got a layout with correct names, I mean Special[0].Id, Speacial[0].Category, etc.
Now, I want to create an empty template. For now I am using mustache template, it should have the same layout as editor template:
<script type="text/template">
<input name="Special[{{itemIndex}}].Category"
</script>
The problem is, that I use the same layout in two different places - in mustache template as well as in razor editor template.
If I need to change this layout - I need to change it in two places. I want to avoid this.
Another problem is that I need hardcode names ("Speacial" in this example) and manually put index, category and etc.
Whatever solution you use, JavaScript will be required. jQuery is just a JavaScript framework, so you could switch it out with something else, if you preferred, but you should stick with some sort or JavaScript framework, as the code for doing XMLHttpRequest cross-browser is tedious and prone to error.
As for your HTML, you can choose to either include it as a template on page load or request it fresh via an AJAX request. Personally, I'd go with a template because AJAX doesn't really buy you anything in this scenario, and it's just an extra request.
Either way, you're unfortunately not going to be able to use the Razor HtmlHelper methods, at least without mangling the HTML afterwards via JavaScript anyways; they simply won't generate the proper naming convention required for binding list objects outside of a for loop. The model-binding convention is easy to replicate manually, though, it's just:
YourCollection[N].FieldName
So if you had a list of Cars on your model and you wanted a field to edit the Color of the 3rd car, you would use:
Cars[2].Color
Any good JavaScript templating solution should be able to automatically insert the N value based on the object's position in the list of other objects.
You can use a string builder to dynamically create the html in the get method of your controller and then post that to the view. The other way is to create your own htmlhelper.
Partialview is the solution:
you can create a partial view and have it added every time you want it to be used or injected into the view. you can run a for or foreach look on that partial view and have it repeat as many times as you want.
1: create a partialview.
2: put everything you want to be rendered 2 times in the partial view.
3: replace the view code with partial view. like:
#html.Partial("~/views/partials/_samplename.cshtml")
you can repeat this partial view anywhere in the project and by changing anything in the partialview it would change everywhere.

Categories

Resources