MvcHtmlString with Razor statements included - razor

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");

Related

How to change culture class programmatically (Calling implemented Switch)

I have implemented culture in my system. The change with selected combox works fine.
[
[
Now I want depending on User Language to change the language.
I read other descriptions but I can't get it to work.
======================= My switch class Model ===================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
namespace WorkCollaboration.Models
{
public class SwitchCultureModel
{
public CultureInfo CurrentUICulture { get; set; }
public List<CultureInfo> SupportedCultures { get; set; }
}
}
I have a general logon service where I check user privileges languages....
In the system I created a page were I want to change User language session and so on.
This is how my page looks like
[
========= This is my razor page ==========
#page
#using Microsoft.AspNetCore.Localization
#using Microsoft.AspNetCore.Mvc.Localization
#model WorkCollaboration.Pages.LogonService.LanguageModel
#{
ViewData["Title"] = "UserLanguage";
}
#inject IViewLocalizer Localizer
<h1>#Localizer["Edit"]</h1>
<h4>#Localizer["LogonService"]</h4>
<p>
<a asp-page="/LogonService/IndexLanguage">#Localizer["Back to Index"]</a>
</p>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="LogonService.WorkColUserMail" />
<input type="hidden" asp-for="LogonService.WorkColUserId" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColUserPassword" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColUserPasswordConfirm" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColUserName" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColUserVerificationMode" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColEnteredPassword" class="form-control" />
<input type="hidden" asp-for="LogonService.WorkColLoggedIn" class="form-control" />
<div class="form-group">
#Html.LabelFor(model => model.LogonService.WorkColUserLanguage, htmlAttributes: new { #class = "form-group" })
<div class="form-group">
#Html.DropDownListFor(model => model.LogonService.WorkColUserLanguage, new List<SelectListItem>
{
new SelectListItem {Text = "DE", Value = "DE", Selected = true },
new SelectListItem {Text = "EN", Value = "EN" },
}, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.LogonService.WorkColUserLanguage, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="/LogonService/IndexLanguage">#Localizer["Back to List"]</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
In c# I call the following threds
if (LogonService.WorkColUserLanguage == "DE")
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("de");
Thread.CurrentThread.CurrentUICulture = new
CultureInfo("de");
}
if (LogonService.WorkColUserLanguage == "EN")
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("en");
Thread.CurrentThread.CurrentUICulture = new
CultureInfo("en");
}
However the page language continues on same language
==========Here my c# code ======================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualBasic;
using WorkCollaboration.Data;
using WorkCollaboration.Models;
using System.Collections;
using System.Web;
namespace WorkCollaboration.Pages.LogonService
{
public class LanguageModel : PageModel
{
private readonly WorkCollaboration.Data.WorkCollaborationContext _context;
public LanguageModel(WorkCollaboration.Data.WorkCollaborationContext context)
{
_context = context;
}
[BindProperty]
public Models.LogonService LogonService { get; set; }
public async Task<IActionResult> OnGetAsync(string id)
{
if (id == null)
{
return NotFound();
}
LogonService = await _context.LogonService.FirstOrDefaultAsync(m => m.WorkColUserMail == id);
if (LogonService == null)
{
return NotFound();
}
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
string id = LogonService.WorkColUserMail;
byte[] ep = LogonService.WorkColEnteredPassword;
string ln = LogonService.WorkColUserLanguage;
string SessionKeyName = "_Name";
string SessionKeyId = "_Id";
string SessionKeyDate = "_Date";
string SessionKeyLang = "_Lang";
if (id == null)
{
return NotFound();
}
//====================================
// Load WorColUser Data with Mail Key
//====================================
LogonService = await _context.LogonService.FirstOrDefaultAsync(m => m.WorkColUserMail == id);
//====================================
// Overwrite Data with GUI Data
//====================================
LogonService.WorkColEnteredPassword = ep;
LogonService.WorkColUserLanguage = ln;
LogonService.WorkColLoggedIn = true;
//====================================
// Create SessionID
//====================================
DateTime now = DateTime.Now;
string valueSystemKeyDates = now.ToString("yyyymmddhh:mm:ss");
HttpContext.Session.SetString(SessionKeyDate, valueSystemKeyDates);
HttpContext.Session.SetString(SessionKeyId, Convert.ToString(LogonService.WorkColUserId));
HttpContext.Session.SetString(SessionKeyName, LogonService.WorkColUserMail);
HttpContext.Session.SetString(SessionKeyLang, LogonService.WorkColUserLanguage);
var SessionIdDate = HttpContext.Session.GetString(SessionKeyDate);
var SessionIdId = HttpContext.Session.GetString(SessionKeyId);
var SessionIdName = HttpContext.Session.GetString(SessionKeyName);
var SessionIdLang = HttpContext.Session.GetString(SessionKeyLang);
LogonService.WorkColUserSessionId = Strings.RTrim(SessionIdDate) + " " + Strings.RTrim(SessionIdName) + " " + Strings.RTrim(SessionIdId) + " " + Strings.RTrim(SessionIdLang);
//=========================================
// Change Culture on specific user language
//=========================================
if (LogonService.WorkColUserLanguage == "DE")
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("de");
Thread.CurrentThread.CurrentUICulture = new
CultureInfo("de");
}
if (LogonService.WorkColUserLanguage == "EN")
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("en");
Thread.CurrentThread.CurrentUICulture = new
CultureInfo("en");
}
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(LogonService).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!LogonServiceExists(LogonService.WorkColUserMail))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("/LogonService/IndexLanguage");
}
private bool LogonServiceExists(string id)
{
return _context.LogonService.Any(e => e.WorkColUserMail == id);
}
}
}
Tks for helping
==============================================================================
Update: 25.1.2021: I investigated further why my culture defined values do not work. And I found the reason why. In my SwithCulturViewComponent.cs The culture is on every page load or exited refreshed to the one defined in the languages in the combo (see Pic 1 or 2)
Now I tried to influence the switch class by setting the culture info from the user language from the session.
=================== SwitchCultureViewComponet ===============
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using WorkCollaboration.Models;
namespace WorkCollaboration.ViewComponents
{
public class SwitchCultureViewComponent : ViewComponent
{
private readonly IOptions<RequestLocalizationOptions> localizationOptions;
public SwitchCultureViewComponent(IOptions<RequestLocalizationOptions> localizationOptions)
{
this.localizationOptions = localizationOptions;
}
public IViewComponentResult Invoke()
{
//=============================================
// Get Session Language
//=============================================
string SessionKeyName = "_Name";
string SessionKeyId = "_Id";
string SessionKeyDate = "_Date";
string SessionKeyLang = "_Lang";
var SessionIdDate = HttpContext.Session.GetString(SessionKeyDate);
var SessionIdId = HttpContext.Session.GetString(SessionKeyId);
var SessionIdName = HttpContext.Session.GetString(SessionKeyName);
var SessionIdLang = HttpContext.Session.GetString(SessionKeyLang);
if (SessionIdId == null)
{
SessionIdId = "0";
}
if (SessionIdId == "")
{
SessionIdId = "0";
}
if (SessionIdLang == null)
{
SessionIdLang = "DE";
}
if (SessionIdLang == "")
{
SessionIdLang = "DE";
}
//=========================================
// Change Culture on specific user language
//=========================================
if (SessionIdLang == "DE")
{
CultureInfo myCIintl = new CultureInfo("de-CH", false);
CultureInfo current = CultureInfo.CurrentCulture;
Console.WriteLine("The current culture is {0}", current.Name);
CultureInfo newCulture;
newCulture = new CultureInfo("de-CH");
CultureInfo.CurrentCulture = newCulture;
Console.WriteLine("The current culture is now {0}",
CultureInfo.CurrentCulture.Name);
CultureInfo.CurrentUICulture = new CultureInfo("de-CH", false);
// CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("de-CH");
Console.WriteLine("CurrentUICulture is now {0}.", CultureInfo.CurrentUICulture.Name);
}
if (SessionIdLang == "DE")
{
CultureInfo myCIintl = new CultureInfo("en-US", false);
CultureInfo current = CultureInfo.CurrentCulture;
Console.WriteLine("The current culture is {0}", current.Name);
CultureInfo newCulture;
newCulture = new CultureInfo("en-US");
CultureInfo.CurrentCulture = newCulture;
Console.WriteLine("The current culture is now {0}",
CultureInfo.CurrentCulture.Name);
CultureInfo.CurrentUICulture = new CultureInfo("en-US", false);
// CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("de-CH");
Console.WriteLine("CurrentUICulture is now {0}.", CultureInfo.CurrentUICulture.Name);
}
// How can I influence this code below. I only want this to be executed when I change the UI language code in the dropdown
// Otherwise it should use the custure Info from the above user languages
var cultureFeature = HttpContext.Features.Get<IRequestCultureFeature>();
var model = new SwitchCultureModel
{
SupportedCultures = localizationOptions.Value.SupportedUICultures.ToList(),
CurrentUICulture = cultureFeature.RequestCulture.UICulture
};
return View(model);
}
}
}
How can I influence this code below? I only want this to be executed when I change the UI language code in the dropdown
Otherwise it should use the culture Info from the above user languages
Whenever I try to CurrentUICuture within the "var"...
============ Section in the SwitchViewComponent.cs ==============
var model = new SwitchCultureModel
{
SupportedCultures =
localizationOptions.Value.SupportedUICultures.ToList(),
CurrentUICulture = cultureFeature.RequestCulture.UICulture
};
return View(model);
I get errors. Thank you for your support

Textbox rejecting ##,00 format

I have a MVC project where I am displaying currency amounts in different formats based on the currency of the object.
My project handles the ##.00 format just find, but I have some objects that are using Euros for example that need to be in the ##,00 format instead of ##.00.
Then the page loads in read only mode both formats display correctly, but then the form is edited, it initially shows the currencies correctly, but if I click out of a Euro formatted amount, it drops the "," out of the amount (for example 1000,00 changes to 100000).
In the model, the fields are of DataType = Currency and are decimals. Also, if 1000,00 is tried to save, it is returned as invalid.
How to I get the textbox to handle the both currency formats?
This is my code
#model Projections.Web.ViewModels.Projections.ProjectionFormView
#Html.HiddenFor(model => model.Number)
#Html.HiddenFor(model => model.Department)
#* -- Quarters -- *#
<div class="edit-fields">
<div class="control-group">
#Html.LabelFor(model => model.Q12017, new {#class = "control-label"})
<div class="controls">
#Html.EditorFor(model => model.Q12017)
</div>
</div>
<div class="control-group">
#Html.LabelFor(model => model.Q22017, new {#class = "control-label"})
<div class="controls">
#Html.EditorFor(model => model.Q22017)
</div>
</div>
<div class="control-group">
#Html.LabelFor(model => model.Q32017, new {#class = "control-label"})
<div class="controls">
#Html.EditorFor(model => model.Q32017)
</div>
</div>
<div class="control-group">
#Html.LabelFor(model => model.Q42017, new { #class = "control-label" })
<div class="controls">
#Html.EditorFor(model => model.Q42017)
</div>
</div>
<div class="control-group">
#Html.LabelFor(model => model.Q12018, new { #class = "control-label" })
<div class="controls">
#Html.EditorFor(model => model.Q12018)
</div>
</div>
</div>
Controller:
public ActionResult Edit(string number, string department)
{
// Get the project we're trying to edit a projection for.
var projects = _db.Projects.FindBy(
x => x.Number == number &&
x.PMUsername == SessionWrapper.CurrentManager,
null,
"Projection").ToList();
if (!projects.Any())
{
return Error(
Notices.ProjectNotFoundTitle,
string.Format(Notices.ProjectNotFound, number)
);
}
var project = projects.SingleOrDefault(x => x.Department == department);
var baseProject = projects.SingleOrDefault(x => x.Department == string.Empty);
// Project doesn't exist, error time!
if (project == null || baseProject == null)
{
return Error(
Notices.DepartmentNotFoundTitle,
string.Format(Notices.DepartmentNotFound, department, number)
);
}
project.Projection = project.Projection ?? new Projection { Number = number, Department = department, Project = project };
SetProjectCulture(project.ProjectCurrencyCode);
var projection = Mapper.Map<ProjectionFormView>(project.Projection);
projection.BaseProjectName = baseProject.Name;
return View(projection);
}
private void SetProjectCulture(string currencyCode)
{
var uiHelper = DependencyResolver.Current.GetService<IThreadUIHelper>();
if (!uiHelper.SetUICulture(currencyCode)) return;
var notice = new Notification(string.Format(Notices.ProjectCurrencyNotice, currencyCode));
NotificationHandler.AddNotification(notice);
}
Model
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Projections.Web.ViewModels.Projections
{
public class Forecast : INotifyPropertyChanged
{
private decimal _q12017;
private decimal _q22017;
private decimal _q32017;
private decimal _q42017;
private decimal _q12018;
[DataType(DataType.Currency)]
public decimal Q12017
{
get { return _q12017; }
set { _q12017 = value; ForecastChanged("Q12017"); }
}
[DataType(DataType.Currency)]
public decimal Q22017
{
get { return _q22017; }
set { _q22017 = value; ForecastChanged("Q22017"); }
}
[DataType(DataType.Currency)]
public decimal Q32017
{
get { return _q32017; }
set { _q32017 = value; ForecastChanged("Q32017"); }
}
[DataType(DataType.Currency)]
public decimal Q42017
{
get { return _q42017; }
set { _q42017 = value; ForecastChanged("Q42017"); }
}
[DataType(DataType.Currency)]
public decimal Q12018
{
get { return _q12018; }
set { _q12018 = value; ForecastChanged("Q12018"); }
}
public decimal Total
{
get
{
var quarters = GetType().GetProperties().Where(x => x.Name.StartsWith("Q")).ToList();
return quarters.Sum(q => (decimal?)q.GetValue(this, null) ?? default(decimal));
}
}
public DateTime? Modified { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void ForecastChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public decimal? this[string name]
{
get
{
var property = GetType().GetProperty(name);
if (property == null) throw new InvalidOperationException("Invalid property specified.");
if (property.PropertyType == typeof(decimal))
{
return property.GetValue(this, null) as decimal?;
}
throw new InvalidOperationException("Invalid property specified.");
}
}
}
}
The default model binder will only handle decimals with a U.S.-style decimal point (.). If you need to accept a comma, you need a custom model binder. I use the following, which I found original here.
public class DecimalModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext) {
ValueProviderResult valueResult = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName);
ModelState modelState = new ModelState { Value = valueResult };
object actualValue = null;
try {
actualValue = Convert.ToDecimal(valueResult.AttemptedValue,
CultureInfo.CurrentCulture);
}
catch (FormatException e) {
modelState.Errors.Add(e);
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return actualValue;
}
}
Then, register it in Application_Start in Global.asax:
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
You may need to alter the model binder to your specific usage scenario. This version simply converts based on the current culture, but you may need to do some different type of processing here if you're going to be handling both periods and commas as "decimal points".

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

MVC3 - Razor: How to use html tag in ActionLink Name

I have a action link on my MVC3 razor view. Which have a action link as bellow:
#Html.ActionLink("Click Here (I do not have Middle Name)",
"", "", new { #class = "button lines-6" })
I want to change action link text to:
<strong>Click Here </strong> (I do not have Middle Name)
Is there any way to sort it out.
Many Thanks
Using the URL.Action instead of an action link you have more control over the contents.
<a href="#Url.Action("Index", "Home")" class="button lines-6">
<strong>Click Here </strong> (I do not have Middle Name)
</a>
A custom HtmlHelper extension is another option.
public static string ActionLinkSpan( this HtmlHelper helper, string linkText, string actionName, string controllerName, object htmlAttributes )
{
TagBuilder spanBuilder = new TagBuilder( "span" );
spanBuilder.InnerHtml = linkText;
return BuildNestedAnchor( spanBuilder.ToString(), string.Format( "/{0}/{1}", controllerName, actionName ), htmlAttributes );
}
private static string BuildNestedAnchor( string innerHtml, string url, object htmlAttributes )
{
TagBuilder anchorBuilder = new TagBuilder( "a" );
anchorBuilder.Attributes.Add( "href", url );
anchorBuilder.MergeAttributes( new ParameterDictionary( htmlAttributes ) );
anchorBuilder.InnerHtml = innerHtml;
return anchorBuilder.ToString();
}
You may also try a different flavor of above suggested option:
<li id="home_nav"><span>Span text</span></li>

How to disable input field's autocomplete with EditorFor?

<%= 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));
}