How to disable input field's autocomplete with EditorFor? - html

<%= Html.EditorFor(product => product.Name) %>
I need the generated output to have autocomplete="off" attribute set.
What I'm missing?
Edit:
I'm looking an extension method for EditorFor that accepts key/value dictionary for attributes, so I can call it like this: <%= Html.EditorFor(product => product.Name, new { autocomplete = "off" } ) %>
Here it is done for LabelFor, but it is needed to be adjusted for EditorFor
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes) {
return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
}
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
if (String.IsNullOrEmpty(labelText))
{
return MvcHtmlString.Empty;
}
TagBuilder tag = new TagBuilder("label");
tag.MergeAttributes(htmlAttributes);
tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.SetInnerText(labelText);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
Edit2:
I realized it can't be named EditorFor because there already exists an overridden EditorFor that accepts an anonymous type, see here http://msdn.microsoft.com/en-us/library/ff406462.aspx.. anyway, we can name it differently, no biggies.

You'll need to use use a custom template that generates the input element with the attribute or you could add some javascript to the page to add the attribute client-side.
<%= Html.EditorFor( product => product.Name, "NoAutocompleteTextBox" ) %>
Then in Shared/EditorTemplates you need a NoAutocompleteTextBox.ascx that defines
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue,
new { autocomplete = "off" }) %>
or, the jQuery way, to set it on all text inputs
$(function() {
$('input[type=text]').attr('autocomplete','off');
});

public static MvcHtmlString EditorForAttr<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes) {
return EditorForAttr(html, expression, new RouteValueDictionary(htmlAttributes));
}
public static MvcHtmlString EditorForAttr<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes) {
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
TagBuilder tag = new TagBuilder("input");
tag.GenerateId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.MergeAttribute("name", htmlFieldName);
tag.MergeAttribute("type", "text");
tag.MergeAttribute("value", metadata.Model == null ? "" : metadata.Model.ToString()); // Not sure if this is correct.
tag.MergeAttributes(htmlAttributes, true);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
}

Related

Adding a dynamic list of parameters with Html helper

I'd like to be able to feed in a list of parameter names and values into a Html.Actionlink but the helper doesn't create the parameters as I would like. Any ideas how to do this?
public class ParameterNameValue
{
public string ParameterName { get; set; }
public string ParameterValue { get; set; }
}
View
#foreach (var action in post.FeedActions)
{
var parameters = "";
foreach (var param in action.Parameters)
{
parameters += param.ParameterName + "=" + param.ParameterValue + ",";
}
#Html.ActionLink(#action.Label, action.ActionName,
new { controller = action.Controller, id = action.CommunityId, slug = action.Slug,
Fromfeed=true,parameters }, new { #class = action.Classes })
}
yields a link like this:
Whereas I need the parameters part to look like:
?FromFeed=true&MatchId=1234&InnerId=5678
edit: I got it working by just manually creating the tag, but no doubt there's a nice way of doing this by creating a custom helper.
#action.Label
I'd suggest you to extend the classic ActionLink helper with a prototype similar to this (add a parameter for your specific class) :
public static MvcHtmlString ActionLinkCustom(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, List<ParameterNameValue> yourOtherValues)
In the code, check if you got any custom values. If such, add them to the RouteValuesDictionnary. Then use the classic ActionLink helper providing this modified RouteValuesDictionnary.
Note : you can work on the routeValues using this
IDictionary<string, object> RouteValues = HtmlHelper.ObjectToDictionary(routeValues);

how to create HTML Helper to extend TextBoxFor?

Hi I've got following line of code:
#Html.TextBoxFor(m => m.StartDate,"{0:MM/dd/yy hh:mm:ss}",new{#class="form-control axDateTimePicker"})
How to write helper to look like
#Html.DateTimePickerHelper(m=>m.StartDate)
where the format string and classes are inside this new helper?
For this you need to create custom html helpers by using extension method
Try the below code
namespace System.Web.Mvc
{
public static class CustomHtmlHelpers
{
public static MvcHtmlString DateTimePickerHelper<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
var attributes = new RouteValueDictionary(htmlAttributes);
string format = "{0:MM/dd/yy hh:mm:ss}";
return System.Web.Mvc.Html.InputExtensions.TextBoxFor(htmlHelper, expression, format, attributes);
}
}
}

MvcHtmlString with Razor statements included

I find myself repeating this code block too often...
<div class="form-group">
<div class="col-sm-3 control-label">
#Html.LabelFor(m => m.Name)
</div>
<div class="col-sm-9">
#Html.TextBoxFor(m => m.Name, null, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Name)
</div>
</div>
I have been attempting to create a MvcHtmlString custom extension, but it assumes that the #Html.LabelFor commands are text and that is what is displayed.
EDIT: Thanks Joe and Stephen!! That's what I was missing.
Here's the final answer for my code block
static MvcHtmlString BaseFieldFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, string>> expression, MvcHtmlString innerHtml, string style = null) {
var labelDiv = new TagBuilder("div");
labelDiv.AddCssClass("col-sm-3 control-label");
labelDiv.InnerHtml += helper.LabelFor(expression, new {
htmlAttributes = new { #class = "form-control" }
});
var textDiv = new TagBuilder("div");
textDiv.AddCssClass("col-md-9");
textDiv.InnerHtml += innerHtml;
textDiv.InnerHtml += helper.ValidationMessageFor(expression);
var groupDiv = new TagBuilder("div");
groupDiv.AddCssClass("form-group");
groupDiv.InnerHtml += labelDiv;
groupDiv.InnerHtml += textDiv;
return new MvcHtmlString(groupDiv.ToString(TagRenderMode.Normal));
}
and for usage
public static MvcHtmlString FieldFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, string>> expression, string style = null) {
var innerHtml = helper.TextBoxFor(expression, null, new { #class = "form-control", style });
return BaseFieldFor(helper, expression, innerHtml, style);
}
public static MvcHtmlString DropDownListFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, string>> expression, IEnumerable<SelectListItem> list, string style = null){
var innerHtml = helper.DropDownListFor(expression, new SelectList(list, "Value", "Text"), new { #class = "form-control", style });
return BaseFieldFor(helper, expression, innerHtml, style);
}
And now I can use it simply!
<div class="panel-body form-horizontal">
#Html.FieldFor(m => m.Name)
#Html.FieldFor(m => m.Address1)
#Html.FieldFor(m => m.Address2)
#Html.FieldFor(m => m.City)
#Html.DropDownListFor(m => m.State, AllowableValues.StateList, "max-width: 200px;")
#Html.FieldFor(m => m.PostalCode, "max-width: 150px;")
#Html.FieldFor(m => m.Phone, "max-width: 150px;")
</div>
Your helper needs to use the inbuilt helper methods for generating your html. For example
MvcHtmlString label = LabelExtensions.LabelFor(helper, expression});
Refer this example for creating a helper that outputs similar html including the label, textbox and validation message.
You're not able to invoke the HTML helpers in the manner that you're trying to do so. All it will do is treat it as text out output the result as you've already seen.
Instead you need to reference the HTML helper along the lines of this:
string yourString = "Your string " + helper.LabelFor("text", "actionName");

HtmlHelper on ActionLink in Razor

I use MVC3 Razor and have a link
Edit
I have written HtmlHelper
public static MvcHtmlString MyHelper(this HtmlHelper helper, string name, string href, string #class = null)
{
var builder = new TagBuilder("a");
builder.MergeAttribute("href", href);
builder.AddCssClass(#class);
builder.InnerHtml = name;
return new MvcHtmlString(builder.ToString());
}
and this link is bad
#Html.MyHelper("Edit","#Url.Action('Edit', 'Obj', new { id = RSAuth.UserId })", "gray-butt right")
Can you try this?
#Html.MyHelper("Edit",Url.Action('Edit', 'Obj', new { id = RSAuth.UserId }), "gray-butt right")
remove the quote for Url.Action, because it is a function that return a string

Set optional disabled attribute

I want to disable all fields in my form, which have values when page is loaded.
For example in this
<td>#Html.TextBoxFor(m => m.PracticeName, new { style = "width:100%", disabled = Model.PracticeName == String.Empty ? "Something Here" : "disabled" })</td>
I want to write inline something like this. I don't want to use if-else and make my code larger.
Using javascript/jquery doesn't welcome too.
I tried to write false/true, but 1.It maybe isn't cross-browser 2.Mvc parsed it to string like "True" and "False".
So how can I do it?
P.S. I use ASP.NET MVC 3 :)
Seems like a good candidate for a custom helper:
public static class HtmlExtensions
{
public static IHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> ex,
object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(ex, attributes);
}
}
which could be used like this:
#Html.TextBoxFor(
m => m.PracticeName,
new { style = "width:100%" },
Model.PracticeName != String.Empty
)
The helper could obviously be taken a step further so that you don't need to pass an additional boolean value but it automatically determines whether the value of the expression is equal to default(TProperty) and it applies the disabled attribute.
Another possibility is an extension method like this:
public static class AttributesExtensions
{
public static RouteValueDictionary DisabledIf(
this object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return attributes;
}
}
which you would use with the standard TextBoxFor helper:
#Html.TextBoxFor(
m => m.PracticeName,
new { style = "width:100%" }.DisabledIf(Model.PracticeName != string.Empty)
)
I used Darin's answer. However, when it came to data_my_custom_attribute, they were not rendered as data-my-custom-attribute. So I changed Darin's code to handle this.
public static RouteValueDictionary DisabledIf(
this object htmlAttributes,
bool disabled
)
{
RouteValueDictionary htmlAttributesDictionary
= HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (disabled)
{
htmlAttributesDictionary["disabled"] = "disabled";
}
return new RouteValueDictionary(htmlAttributesDictionary);
}