That is a tricky question because I want to add Html Attributes to the EditorFor() but do not want to replace the ones that was already created. Let me explain:
I have a default Editor Template for string.cshtml with the following code:
#{
var htmlAttributes = ViewData;
htmlAttributes["class"] = "text-box single-line form-control";
htmlAttributes["placeholder"] = ViewData.ModelMetadata.Watermark ?? ViewData.ModelMetadata.DisplayName;
htmlAttributes["title"] = ViewData.ModelMetadata.Watermark ?? ViewData.ModelMetadata.DisplayName;
}
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, htmlAttributes)
It is used to always add the following class, placeholder and title, based on the DisplayName DataAnnotation, for the Form Inputs, it is quite handy!
But the problem is that I'm having trouble adding the disable attribute for one specific Form Input with the common code:
#Html.EditorFor(x => x.Field, new { htmlAttributes = new { disabled = "" } })
When the Form Input is with a field that is not a string, it will not follow the created EditorTemplate and it will work with this exactly code, but when it is a string, the EditorTemplate replaces the Html Attributes.
Does anyone has any clue on this?
Turns out there was a few dumb errors, first of all the declaration on the EditorFor() field was wrong, the correct one is this:
#Html.EditorFor(x => x.Field, new { #disabled = "" })
The second point is to keep using the incoming htmlAttributes in the string.cshtml EditorTemplate, replacing the class property definition:
htmlAttributes["class"] = "text-box single-line form-control";
For:
htmlAttributes["class"] = htmlAttributes["class"] + "text-box single-line form-control";
In this way, the incoming html attributes is just concatenated with the new default ones.
Related
I'm trying to use EditorFor custom templates.
I want to create a Int32 and decimal templates to render the inputs with some validations.
This is what I'm trying
#model int?
#Html.TextBoxFor(model => model, null, new { #type="text", #oninput = "this.value=this.value.replace(/[^0-9]/g,'')" } )
And I call it like
#Html.EditorFor(x => x.ExampleIntField)
It renders an <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')"
To here everything works, but when I try to pass extra htmlAttributes like readonly I don't understand how I must receive it in EditorFor template.
Example
#Html.EditorFor(x => x.ExampleIntField, new { htmlAttributes = new { #readonly = "readonly" } } )
I tried this I got the exact same <input type="text", oninput="this.value=this.value.replace(/[^0-9]/g,'')" rendered without readonly attribute
You are using the overload of EditorFor() that passes the object as additionalViewData. You can read that within the template from the ViewDataDictionary
#model int?
#{ var attributes = ViewData["htmlAttributes"]; } // returns { #readonly = "readonly" }
which you could then merge with your existing attributes and use in the TextBoxFor() method.
#{
var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(attributes);
htmlAttributes.Add("oninput", "this.value=this.value.replace(/[^0-9]/g,'')";
}
#Html.TextBoxFor(model => model, htmlAttributes)
Note that TextBoxFor() generates type="text" so there is no need to add it again. In addition, you do not need the leading # unless its a reserved keyword (for example #class = "...")
I am trying to populate textarea using the input value. But it is not working. Any solution to this issue?
#Html.EditorFor(model => model.ModelName, new { htmlAttributes = new { #class = "textbox-css", #Value = "ViewData.Model.ModelName" } })
You can remove quotes from #Value = "ViewData.Model.ModelName", because you are sending a string to Value property, not the content of ModelName property.
But why don't you use the TextArea helper? Like:
#Html.TextAreaFor(model => model.ModelName, new { htmlAttributes = new { #class = "textbox-css" })
It's not common set the value property like you are doing, I don't know if it works, actually. I think this is not a good way to do that. You should use the TextAreaFor(x => x.Property) or EditFor(x => x.Property) directly, instead of set the value property, as I said.
you don't need to manually populate the value property with the ViewData, remove the #Value = "ViewData.Model.ModelName". I think the problem is your ViewData name conflict with the property of the model (both have the name "ModelName").
Try changing the ViewData property name to something else. Works for me when I have an issue with unpopulated DropDownListFor
Most of the Html helpers available in ASP.Net MVC have overloads with object htmlAttributes. This is used to provide additional attribute values for the outputted tags. While using the anonymous object notation for specifying htmlAttributes value, their property names must be valid c# identifier.
Now the problem arises when you are trying to output a property with a dash - character (for e.g. knockout js's "data-bind" attribute)
So for example lets take the following example:
#Html.TextBox("Title", string.Empty, new { data-bind="text: title" })
Try the above code in your view and at run-time it would show error screen with below message:
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.
So the question is, how to provide htmlAttributes with their property keys having dash characters; like "data-bind"?
In your property names, replace all your dash - characters with an underscore _ (as shown in example below):
#Html.TextBox("Title", string.Empty, new { data_bind="text: title" })
This would work because all HTML helpers convert an underscore _ in a property name to a dash - when rendering the HTML; i.e. for your example, data_bind when outputted in html gets converted to data-bind.
This is not always correct. Say you're using parameters in a URL.
#Html.ActionLink("Add Job", "Index", "Home", new { foo_bar = "foobar" }, new { #class = "btn btn-default", data_foo = "bar" })
The data_foo does get rendered as "data-foo", but the parameters stays as a under bar. Your result will be: http://your.domain/yourapp/?foo_bar=foobar
Of course you can't actually use the dash or you get the error specified in the OP.
I have worked around this as follows, but I'd be interested to see if anyone that comes along in the future will have a better way:
#{
var link = Html.ActionLink("Add Job", "Index", "Home", new { foo_bar = "foobar" }, new { #class = "btn btn-default", data_foo = "bar" });
}
#Html.Raw(link.ToString().Replace('_', '-'))
Use the HtmlHelper.AnonymousObjectToHtmlAttributes method. The following code will add a tooltip to the text input box, with the tooltip displaying the data from the DisplayAttribute description for MyIntVal on my model.
#{
var htmlAttributesWithDashes = HtmlHelper.AnonymousObjectToHtmlAttributes(
new
{
id = "myTextBoxId",
data_toggle = "tooltip",
data_position = "left top",
title = ModelMetadata.FromLambdaExpression( m => m.MyIntVal, ViewData ).Description
}
);
}
<div class="col-sm-6">
#Html.TextBoxFor( m => m.MyIntVal, htmlAttributesWithDashes )
</div>
Is it possible when using Html.TextBoxFor to override the name attribute?
I have tried with no success. I need to use TextBoxFor to get client side validation to work, however for reasons I won't go into I need the name of the textbox to be different from the generated one.
I have tried the following:
#Html.TextBoxFor(x => x.Data, new { name = Model.Key + "_Data", id = Model.Key + "_Data" })
Which works for ID but not name. Is this possible?
Update: Looking into the code for TextBoxFor. It doesn't look like there is an easy way. Hopefully someone can prove me wrong.
Rob, actually there is a much simpler way. Instead of name, use Name:
#Html.TextBoxFor(x => x.Data, new { Name = Model.Key + "_Data", id = Model.Key + "_Data" })
Are you asking this because you want to apply a prefix to the name? If so, you can do this by setting ViewData.TemplateInfo.HtmlFieldPrefix in your Controller.
I learnt a lot about this stuff from Brad Wilson's blog.
EditorFor has an overload where you can supply the name attribute as a parameter:
#Html.EditorFor(expression, null, name)
Try EditorFor. you can pass string as template name if you want to make sure textbox is rendered even if property type is not string. If property is string already, it does not need templatename explicitly to render textbox, so you can pass null. Note that it does not require id parameter explicitly, it will infer it from element name. And all the validation things are still active with EditorFor
#Html.EditorFor(x => x.Data, "string", Model.Key + "_Data")
It is called Microsoft GOTCHA...
Use the name in caps, like this
#Html.TextBoxFor(m => m.Reply.Answer, new { Name = "Whatyouwant" })
ben's answer got me what I was looking for except you need to wrap in in Html.Raw
#Html.Raw(Html.TextBoxFor(x => x.Data).ToString().Replace("Data", "NewData"))
a little bit "unpretty"=), try:
#Html.TextBoxFor(x => x.Data).ToString().Replace("Data", "NewData")
For me, it works! I hope that help!
#Html.EditorFor(model => model.Nome, new { htmlAttributes = new { #class = "form-control", #maxlength = "80", #id = "NomeFilter", #Name = "NomeFilter" } })
#Html.EditorFor(Model => Model.Something, "name", "name", new {#class = "form-control" })
Not sure which of those two string parameters in the middle do the work, but it worked only when I typed both of them.
For this example, I was disabling form fields based on permissions, but still showing them. I had a hidden field to send the value to the controller, but wanted a different field name in the EditorFor.
First param after model value represents the "name" property, second is the new name.
#Html.EditorFor(m => m.UserName, "name", "UserNameDisabled", new { htmlAttributes = new { #class = "form-control", #disabled = "disabled"} });
Results in:
<input class="form-control text-box single-line" disabled="disabled" id="UserNameDisabled" name="UserNameDisabled" type="text" value="someEnteredValue" />
Keep it simple, your already providing the ID you should simply be able to use the method "TextBox" instead of "TextBoxFor" and it will work fine client side and server side. In addition, although the accepted answer will work but will produce duplicate Name attributes on your tag if you inspect it using a browser. The below solution does not have that problem.
MvcHtmlString Html.TextBox(string name, string value, object htmlAttributes)
#Html.TextBox(Model.Key + "_Data", Model.Key, new { id = Model.Key + "_Data" }
I am kind of stumped because, I want to format the value and add a html attribute for css class.
If I use #Html.TextBoxFor(m => m.DateModified)
- I can add html attribute but formatting does not work via DisplayFormat attribute on the member.
If I use #Html.EditorFor(m => m.DateModified)
- Formatting works but I cannot add html attribute
If I use #Html.TextBox("DateModified", Model.DateModified, ...)
- I get null reference exception when Model is null when the form is in add mode
What is the best way to achieve this?
I ended up solving this by creating a custom editor template for my date picker as so:
Shared/EditorTemplates/DateTime.cshtml
#model System.DateTime?
#Html.TextBox("", Model.HasValue ? Model.Value.ToString("dd/MM/yyyy") : string.Empty, new { #class = "date-picker" })
Then in my original page continue to use
#Html.EditorFor(m => m.DateModified)
You could...
#Html.TextBoxFor(m => m.DateModified, new { Value = Model.DateModified.ToString("MM-dd-yyyy"), #class = "superCoolClassName"})
Use #Html.EditorFor(m => m.DateModified), because otherwise the DisplayFormat attribute will have no effect.
To add further attributes like a CSS class, you have to create an editor template for the DateTime.
Create a file EditorTemplates/DateTime.cshtml with the following content:
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new
{
#class="date"
})
Please note that the value of the TextBox is not set with the Model directly, but rather with the TemplateInfo.FormattedModelValue, because that value will be formatted according to the DisplayFormat attribute while the Model not. (This took me quite some time to realize. :))
In simple cases this might be enough, e.g. if the CSS class can be the same for all date editors.
If you want to parametrize the attribute, you can do that as well, passing the attribute value parameter to the EditorFor.
#Html.EditorFor(m => m.DateModified, new { #class = "someClass" })
However, this parameter will be not automagically delegated to the HTML control as attribute, but you have to "handle it" in the template explicitly. According to my experiences you can access this parameter value in the ViewData in the template, so the parametrized template looks like this:
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new
{
#class=ViewData["class"]
})
To prevent hardcoding the key/value pairs listed in EditorFor , convert the ViewData object to a Dictionary and pass that dictionary object to TextBox.
eg
#Html.EditorFor(m => m.DateModified, "Template", new { #class = "someClass", size=8 , htmlTag="custom" })
And in the template you have
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, ViewData.ToDictionary(c=>c.Key,c=>.Value))
To show json date in textbox (cshtml):
var d1 = ui.item.IssueDate;
var d = new Date(parseInt(d1.slice(6, -2)));
var Issdate = ("0" + (d.getMonth() + 1)).slice(-2) + '/' +
("0" + d.getDate()).slice(-2) + '/' +
d.getFullYear().toString();
$('#IssueDate').val(Issdate);