MVC 4 razor Data Annotations ReadOnly

20,543

Solution 1

You can create a custom helper like this that will check the property for the presence of a ReadOnly attribute:

public static MvcHtmlString MyTextBoxFor<TModel, TValue>(
    this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
    var metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    // in .NET 4.5 you can use the new GetCustomAttribute<T>() method to check
    // for a single instance of the attribute, so this could be slightly
    // simplified to:
    // var attr = metaData.ContainerType.GetProperty(metaData.PropertyName)
    //                    .GetCustomAttribute<ReadOnly>();
    // if (attr != null)
    bool isReadOnly = metaData.ContainerType.GetProperty(metaData.PropertyName)
                              .GetCustomAttributes(typeof(ReadOnly), false)
                              .Any();

    if (isReadOnly)
        return helper.TextBoxFor(expression, new { @readonly = "readonly" });
    else
        return helper.TextBoxFor(expression);
}

The attribute is simply:

public class ReadOnly : Attribute
{

}

For an example model:

public class TestModel
{
    [ReadOnly]
    public string PropX { get; set; }
    public string PropY { get; set; }
}

I have verified this works with the follow razor code:

@Html.MyTextBoxFor(m => m.PropX)
@Html.MyTextBoxFor(m => m.PropY)

Which renders as:

<input id="PropX" name="PropX" readonly="readonly" type="text" value="Propx" />
<input id="PropY" name="PropY" type="text" value="PropY" />

If you need disabled instead of readonly you can easily change the helper accordingly.

Solution 2

You could create your own Html Helper Method

See here: Creating Customer Html Helpers

Actually - check out this answer

 public static MvcHtmlString MyTextBoxFor<TModel, TProperty>(
         this HtmlHelper<TModel> helper, 
         Expression<Func<TModel, TProperty>> expression)
    {
        return helper.TextBoxFor(expression, new {  @readonly="readonly" }) 
    }
Share:
20,543
Soenhay
Author by

Soenhay

Updated on July 09, 2022

Comments

  • Soenhay
    Soenhay almost 2 years

    The ReadOnly attribute does not seem to be in MVC 4. The Editable(false) attribute does not work the way I would want it to.

    Is there something similar that works?

    If not then how can I make my own ReadOnly attribute that would work like this:

    public class aModel
    {
       [ReadOnly(true)] or just [ReadOnly]
       string aProperty {get; set;}
    }
    

    so I can put this:

    @Html.TextBoxFor(x=> x.aProperty)
    

    instead of this ( which does work ):

    @Html.TextBoxFor(x=> x.aProperty , new { @readonly="readonly"})
    

    or this ( which does work but values are not submitted ):

    @Html.TextBoxFor(x=> x.aProperty , new { disabled="disabled"})
    

    http://view.jquerymobile.com/1.3.2/dist/demos/widgets/forms/form-disabled.html

    something like this maybe? https://stackoverflow.com/a/11702643/1339704

    Note:

    [Editable(false)] did not work

  • Soenhay
    Soenhay over 10 years
    That looks promising... I could just create one called ReadOnlyTextBoxFor or something similar.... I suppose the data annotation is overkill.
  • KerSplosh
    KerSplosh over 10 years
    Exactly, and in my opinion doing it this way, you are doing it in the right place. I dont think a data annotation is how you would define what is essentially a presentation attribute
  • Soenhay
    Soenhay over 10 years
    Is there a way to make it work with any Html helper instead of creating a new Html helper?
  • asymptoticFault
    asymptoticFault over 10 years
    Data Annotations can and often do provide information for displaying a property, i.e. the Display and DisplayFormat data annotations.
  • asymptoticFault
    asymptoticFault over 10 years
    There is no way to make it work with all the helpers in the way you are wanting. That is why most of the helpers have the optional htmlAttributes argument that will let you specify things like readonly as needed. My above solution is how you would have to implement it for the requirements you gave, i.e. using an attribute. Another solution, though I don't believe it would be any cleaner than specifying @readonly = "readonly", would be to create an extension to work on the outputted HTML from the helper, i.e. @Html.TextBoxFor().Readonly().
  • Soenhay
    Soenhay over 10 years
    Ok, I decided to just use htmlAttributes as it is way simpler... but I will accept your answer since it seems like the closest answer to my question.