LabeFor doesn't generate display-lable class attribute - css

A new MVC project includes a Site.css which specifies:
/* Styles for editor and display helpers
----------------------------------------------------------*/
.display-label,
.editor-label
{
font-weight: bold;
margin: 1em 0 0 0;
}
However, when I use LabelFor(m=>m.SomeField) the generated html doesn't include the class attribute:
<label for="SomeField">Some Field</label>
I have seen other examples where people are using LabelFor and the generated html does include the class="display-label" attribute.
Is LabelFor supposed to generate this class attribute? If so, why might it be that mine is not?
I do have a custom DataAnnotationsModelMetadataProvider wired up, but it is still calling the base:
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (metadata.DisplayName == null)
metadata.DisplayName = propertyName.ToTitleCaseFromCamel();
return metadata;
}

Those css classes are only there for when you use EditorFor and DisplayFor templates. When just using LabelFor, you need to supply your own css class.

Rossis got me looking at one of my Create pages to verify his claims. As calls to EditorFor and DisplayFor also appeared to not utilize any of these css classes in my project. I started poking around the generated HTML of some of my Create/Edit pages and found the answer.
Those classes are only used in Views generated through the scaffolding options:
<div class="editor-label">
#Html.LabelFor(model => model.MeetingDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MeetingDate)
#Html.ValidationMessageFor(model => model.MeetingDate)
</div>
So you can see the generated page explicitly references the css class. It is not generated from the LabelFor Html helper call. So the class references are a result of the scaffolding, not a result of the Html helper.
Thus I have to explicitly reference them in views that I code from scratch.

Related

Make field disabled using Razor in MVC Core [duplicate]

I want to enable or disable a textarea depending on a condition that evalueates from the model, and I am using the textarea tag helper.
In other words, something like this:
<textarea asp-for="Doc" #(Model.MustDisable ? "disabled" : "")></textarea>
But I got the following design-time error: The tag helper 'textarea' must not have C# in element's attribute declaration area.
Then I tried:
<textarea asp-for="Doc" disabled='#(Model.MustDisable ? "disabled" : "")'></textarea>
which did not show any design time error but it renders like this:
Model.MustDisable==true renders disabled='disabled' AND Model.MustDisable==false renders disabled.
So the text area will always be disabled.
Then I tried (removing the 's):
textarea asp-for="Doc" disabled=#(Model.MustDisable ? "disabled" : "")></textarea>
which did not show any design time error but it renders the same as the previous one.
How can I implement this the right way?
It is actually very simple, the disable attribute is already working as you want - you can pass in a boolean value:
<textarea asp-for="Doc" disabled="#Model.MustDisable"></textarea>
if false the disabled attribute is not rendered:
<textarea></textarea>
if true the disabled attribute is set to "disabled":
<textarea disabled="disabled"></textarea>
I was facing the same issue with select tag helper, i tried few things and it worked.
Try this-
<textarea asp-for="Doc" disabled="#(Model.MustDisable ? "disabled" : null)"></textarea>
The textarea tag helper does not have direct support to conditionally render a disabled text area. But you can always extend the TextAreaTagHelper and add this feature.
So create a new class which inherits from the TextAreaTagHelper class.
[HtmlTargetElement("textarea", Attributes = ForAttributeName)]
public class MyCustomTextArea : TextAreaTagHelper
{
private const string ForAttributeName = "asp-for";
[HtmlAttributeName("asp-is-disabled")]
public bool IsDisabled { set; get; }
public MyCustomTextArea(IHtmlGenerator generator) : base(generator)
{
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (IsDisabled)
{
output.Attributes["disabled"] = "disabled";
}
base.Process(context, output);
}
}
In your _ViewImports.cshtml file, using the #addTagHelper directive, specify the assembly where the above class is defined so that our new tag helper is available in other razor views.
#addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
#addTagHelper "*,YourAssemblyNameHere"
Now in your views, you can use it like
#model YourSomeViewModel
<textarea asp-for="Doc" asp-is-disabled="Model.MustDisable"></textarea>
where SomeViewModel has a Doc and MustDisable property.
public class YourSomeViewModel
{
public string Doc { set;get; }
public bool MustDisable { set;get; }
}
I am posting this separately since I don't have enough reputation to add a comment to Shyju's answer.
If you inherit from one of the default tag helpers and then register both the default tag helpers and your custom tag helper in _ViewImports.cshtml, then both tag helpers will be executed for the specified tags.
For the following:
[HtmlTargetElement("textarea", Attributes = ForAttributeName)]
public class MyCustomTextArea : TextAreaTagHelper
{
private const string ForAttributeName = "asp-for";
...
With the following _ViewImports.cshtml:
#addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
#addTagHelper "*,YourAssemblyNameHere"
Both MyCustomTextArea and TextAreaTagHelper will be executed for each textarea tag.
I did not notice any problems with the output generated for textareas, but I have run into problems inheriting from other default tag helpers. The solution is to remove the default tag helper in _ViewImports.cshtml.
#addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
#addTagHelper "*,YourAssemblyNameHere"
#removeTagHelper "Microsoft.AspNet.Mvc.TagHelpers.TextAreaTagHelper, Microsoft.AspNet.Mvc.TagHelpers"

Asp.net MVC5 with Bootstrap EditorFor size

I have some modifications to bring to a form which use EditorFor (and using MVC5) and I can't find the way of setting the size of the text box ...
I tried the hard way with:
#Html.EditorFor(model => model.Nom, new{#style="width:400px"})
But this did not work..
Is there an easy way?
In MVC up to version 5, EditorFor does not allow you to specify html elements in that way. It can only be used in non-editor contexts, like TextBoxFor, etc...
In MVC 5.1 they added the ability to specify html attributes in Editor templates, and you can now do this:
#Html.EditorFor(model => model, new { htmlAttributes = new { #class = "form-control" }, })
Using MVC 5 - You need to use [DataType(DataType.MultilineText)] attribute on your view model ejm:
using System.ComponentModel.DataAnnotations;
public class Requests
{
[Display(Name = "Id")]
public int RequestId { get; set; }
[DataType(DataType.MultilineText)]
public string Comments { get; set; }
}
It is not a great idea to apply css class to EditorFor template because an EditorTemplate may can have many elements in that. What you can do is to apply your css thing inside your EditorTempalte file. Checkout this answer for more details.
But if you are simply trying to render a textarea, you may simply use the TextAreaFor helper method.
#Html.TextAreaFor(model => model.Nom, new { #class = "myCustomClass" })
and your css
.myCustomClass
{
width:400px;
}
You may use !IMPORTANT if you specifically want to make sure that this css style overrides the eixsting style.
.myCustomClass
{
width:400px !IMPORTANT;
}
the same but in VB
#Html.TextBoxFor(Function(model) model.nit , New With {.class = "form-control"})
If you want to apply it to all your EditorFor, just change the max-width in your Site.css from 280px to any other value.
Example:
textarea {
/*max-width: 280px;*/
max-width: 900px;
}
This worked for me in MVC 5.1

How to add css to a single mvc Helper method when validation fails - from within the model

Does anyone have a simple way of adding a css class to a html label when validation fails, preferably from within the model, in the public IEnumerable Validate(ValidationContext context) override, not with jQuery or in the Controller.
I have my validationsummary giving me the error message I just want to put * next to the failed input and make its label text bold and red.
#Html.LabelFor(model => model.Name)
<div class="editor-field">
#Html.EditorFor(model => model.Name)<br/><br />
</div>
If you have not yet found a solution, look at http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx
It codes an HTML Helper extension to LabelFor that supports html attributes. You could use this code as a template to modify for your needs. One option would be to detect whether a validation error has occured. A few days ago I wrote something similar:
public static string IsInvalidFor<TModel, TValue>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TValue>> expression,
string cssErrorClass)
{
if (ValidationExtensions.ValidationMessageFor(htmlHelper, expression) != null)
return cssErrorClass;
else return "";
}
if you want to do it in .cs file Model in this case just append this
string name = //ur name property//;
oppdesc = "";
oppdesc += "<span class ="error"+ "\">" + name+ "</span>";
and u define class error as bold and red in ur css.

Setting initial text for validation message

I'm currently using ValidationMessageFor to locate and display any errors in my asp.net MVC3 form. To provide this on a client-side level, I'm also using JQuery's unobtrusive validation.
These methods are fantastic but they seem to be lacking one thing - an option to display an initial 'hint' when the user is in a form field, just like on Twitter's sign up form. To clarify, I'd like this to appear in the same place as the validation message.
Can anyone tell me if this functionality is available and if not, how I would go about implementing it?
Just elaborating on my comment above
The way I implemented this was by creating a "HintFor" html extension
public static MvcHtmlString HintFor<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression)
{
dynamic attribute = ModelMetadata.FromLambdaExpression(expression, self.ViewData);
return MvcHtmlString.Create(attribute.Description);
}
which just displays what you set the description property on the Display attribute for that viewmodel property
[Display(Name = "Application Title", Description = "Description goes in here")]
public string Title { get; set; }
Then in my front end I formatted each form step as shown (the extra classes are because I'm using the uni-form library to format my form)
<div class="question">
#Html.LabelFor(m => m.Title, new { #class = "label" })
<div class="formHint">
#Html.HintFor(m => m.Title)
</div>
<div class="response">
#Html.TextBoxFor(m => m.Title, new { #class = "textInput", autocomplete = "off" })
</div>
<div class="sidetip">
#Html.ValidationMessageFor(m => m.Title, null, new { #class = "invalid" })
</div>
</div>
Then using a little CSS I set the "formhint" class to display none when the error message is shown
.validation-summary-valid, .field-validation-valid
{
display: none;
}
.input-validation-error + .formHint
{
display: none !important;
}
Hope this helps

TextBoxFor in EditorTemplate or DisplayTemplate

In our project we are using TextBoxFor in many places.
We would like to set the height and width of the TextBoxFor wherever we have used, for that we have done this.
<%= Html.TextBoxFor(x => x, new { #class = "TextBoxFor" } ) %>
.TextBoxFor
{
height:30px;
width:250px;
font-family:#Batang;
font-size:20px;
font-weight: bold;
}
Is it possible to to put the <%= Html.TextBoxFor("", new { #class = "TextBoxFor" } ) %> somewhere in a EditorTemplate / DisplayTemplate and in other places we just call like this
<%= Html.TextBoxFor(x => x) %>
Which means we are not specifying the css class name. So it is easy to maintain.
Any ideas. Thanks
Update, I created a static helper but it is having errors..
public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
return htmlHelper.CustomTextBoxFor<TModel, TProperty>(expression, new { #class = "TextBoxFor" });
}
<%: Html.CustomTextBoxFor(m => m.Name) %>
Any ideas?
Yes, but you can also create your own Html helper, then do Html.MyTextBoxFor(...).
Check here for examples
You can download the MVC3Futures file, and it includes Templatized versions of the default templates, which you can put in your folder. You can edit these to customize the TextBoxFor used. However, you must use #Html.EditorFor(...) in your view rather than TextBoxFor(). Be aware, this will affect all uses of EditorFor in the scope where the templates are installed.
By the way, if you're using MVC3, I strongly suggest using the Razor engine rather than the WinForms engine. It's less typing, and it's more efficient, and it has features you're not going to get in WinForms.. and it discourages WinForms thinking.
If you want to apply the style for all text input fields you can modify the css style that comes with the MVC template.
input[type="text"]
{
border: 1px solid #ccc;
padding: 2px;
font-size: 1.2em;
color: #444;
}

Resources