I want to be able to display some text, but also have the text be modifiable via jQuery.
<%= Html.DisplayFor(model => model.DeviceComponentName)%>
If I used EditorFor instead of DisplayFor I would see an ID for the input control. I do not want the value to be editable in that way, though. So, I have made it a DisplayFor, but it does not generate an ID property for the element.
Should I just wrap the DisplayFor in a div and do something like:
<div id="<%= ViewData.TemplateInfo.GetFullHtmlFieldName("DeviceComponentName") %>">
<%= Html.DisplayFor(model => model.DeviceComponentName)%>
</div>
$('#DeviceComponentName').text('newValue');
Or is there a cleaner way of achieving this?
Update: Is there a way which doesn't depend on hard-coded strings? Something that ties to the object itself so if my property name changes I'd get a compile error?
Also, I am using this code, but I do not see an ID value appear:
<td class="editableValue">
<%--Label should be editable, so it needs an ID, but only will be edited by jQuery so it can't be an EditorFor--%>
<%= Html.DisplayFor(model => model.DeviceComponentName, new { id = "DeviceComponentName" })%>
<button type="button" id="ComponentTreeButton" class="nestedDialogButton">...</button>
</td>
To avoid 'magic string' inputs (in case your model properties change), you could do this with an extension. It also makes for much cleaner code:
public static MvcHtmlString DisplayWithIdFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string wrapperTag = "div")
{
var id = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(ExpressionHelper.GetExpressionText(expression));
return MvcHtmlString.Create(string.Format("<{0} id=\"{1}\">{2}</{0}>", wrapperTag, id, helper.DisplayFor(expression)));
}
Then simply use it like this:
@Html.DisplayWithIdFor(x => x.Name)
Will produce
<div id="Name">Bill</div>
Or if you want it to be wrapped in a span:
@Html.DisplayWithIdFor(x => x.Name, "span")
Which will make:
<span id="Name">Bill</span>
Non-Razor
For non Razor syntax, you simply use it like this:
<%= Html.DisplayWithIdFor(x => x.Name) %>
and:
<%= Html.DisplayWithIdFor(x => x.Name, "span") %>
you must be use:
Html.DisplayFor(model => model.DeviceComponentName, new { @id = "DeviceComponentName"})
For dynamic id and other properties, i use:
Class for metadata:
public class AdditionalHtml : Attribute, IMetadataAware
{
public string Id { get; set; }
public string Type { get; set; }
public string CssClass { get; set; }
public string PlaceHolder { get; set; }
public string Style { get; set; }
public string OnChange { get; set; }
public int Rows { get; set; }
public int MaxLength { get; set; }
public bool ReadOnly { get; set; }
public bool Disabled { get; set; }
public Dictionary<string, object> OptionalAttributes ()
{
var options = new Dictionary<string, object>();
if ( !string.IsNullOrWhiteSpace( Id ) )
options.Add( "id", Id );
if ( !string.IsNullOrWhiteSpace( Type ) )
options.Add( "type", Type );
if ( !string.IsNullOrWhiteSpace( CssClass ) )
options.Add( "class", CssClass );
if ( !string.IsNullOrWhiteSpace( PlaceHolder ) )
options.Add( "placeholder", PlaceHolder );
if ( !string.IsNullOrWhiteSpace( OnChange ) )
options.Add( "onchange", OnChange );
if ( !string.IsNullOrWhiteSpace( Style ) )
options.Add( "style", Style );
if ( Rows != 0 )
options.Add( "rows", Rows );
if ( MaxLength != 0 )
options.Add( "maxlength", MaxLength );
if ( ReadOnly )
options.Add( "readonly", "readonly" );
if ( Disabled )
options.Add( "disabled", "disabled" );
return options;
}
Class for metadata provider:
public class MetadataProvider : DataAnnotationsModelMetadataProvider
{
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 );
var additionalHtmlValues = attributes.OfType<AdditionalHtml>().FirstOrDefault();
if ( additionalHtmlValues != null )
{
metadata.AdditionalValues.Add( "AdditionalHtml", additionalHtmlValues );
}
return metadata;
}
}
Add helper:
public static class HtmlAttributesHelper
{
public static string GetHtmlAttribute<T> ( this T model, Expression<Func<T, object>> expression, string attribName )
{
string strDefault = String.Empty;
MemberInfo member = null;
switch ( expression.Body.NodeType )
{
case ExpressionType.Lambda:
case ExpressionType.Convert:
{
var body = expression.Body as UnaryExpression;
if ( body == null )
return strDefault;
var operand = body.Operand as MemberExpression;
if ( operand == null )
return strDefault;
member = operand.Member;
break;
}
case ExpressionType.MemberAccess:
{
var body = expression.Body as MemberExpression;
if ( body == null )
return strDefault;
member = body.Member;
break;
}
default:
{
return expression.Body.ToString() + " " + expression.Body.NodeType.ToString();
}
}
if ( member == null )
return strDefault;
var attr = member.GetCustomAttributes( typeof( AdditionalHtml ), false );
if ( attr.Length > 0 )
{
return ( attr [ 0 ] as AdditionalHtml ).OptionalAttributes() [ attribName.ToLower() ].ToString();
}
// Return Name of Property if AdditionalHtml.Id is empty
return attribName == "Id" ? member.Name : strDefault;
}
public static string GetHtmlId<T> ( this T model, Expression<Func<T, object>> expression )
{
return model.GetHtmlAttribute( expression, "Id" );
}
}
Register provider in Global.asax:
protected void Application_Start ()
{
AreaRegistration.RegisterAllAreas();
//....
ModelMetadataProviders.Current = new MetadataProvider();
}
In your model u can use AdditionHtml like as:
[AdditionalHtml( Id = "OrderNo", CssClass = ShortTextStyle, Disabled = true )]
public string OrderNo { get; set; }
And now you can use sintax for js (in view):
$('#@Model.GetHtmlId( x => x.PropertyName)')
And in view, you can use:
@Html.DisplayFor( x => x.FormDate )
Html attributes attached automatically
Just add a HiddenFor above the column. This will give you a ID to use for what you need. Simple and does the trick for you to grab that value by ID.
<%= Html.HiddenFor(model => model.DeviceComponentName)%>
<%= Html.DisplayFor(model => model.DeviceComponentName)%>
HtmlHelpers have overrides that allow you to pass in an object, or a dictionary, to add attributes to the generated html tag:
@Html.DisplayFor(model => model.DeviceComponentName, new { id = "myId" })
@Html.DisplayFor(model => model.DeviceComponentName, new Dictionary<string, object>() { { "id", "myId" } })
or
@Html.DisplayFor(model => model.DeviceComponentName, new { id = ViewData.TemplateInfo.GetFullHtmlFieldName("DeviceComponentName") })
@Html.DisplayFor(model => model.DeviceComponentName, new Dictionary<string, object>() { { "id", ViewData.TemplateInfo.GetFullHtmlFieldName("DeviceComponentName" } })
UPDATE:
After reviewing the updated code, and re-reading the question, here is what I would suggest - which is similar to your first idea.
<td class="editableValue" id="<%= ViewData.TemplateInfo.GetFullHtmlFieldName("DeviceComponentName") %>">
<%= Html.DisplayFor(model => model.DeviceComponentName)%>
<button type="button" id="ComponentTreeButton" class="nestedDialogButton">...</button>
</td>
You shouldn't need to add an extra div inside the TD, because you can modify the value within the td directly via the jQuery. I believe the following should accomplish this:
$('#DeviceComponentName').html('newValue');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With