Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to exclude a field from @Html.EditForModel() but have it show using Html.DisplayForModel()

I am reading up on ASP.NET MVC and all of it's fun uses and I just found out about DataTemplates.

In my hurry to test this thing out, I converted one of my simpler models over to using @Html.DisplayForModel() and @Html.EditForModel() and it worked like a lucky charm that it is :)

One thing that I immediately found out though was that I could not easily define a field to show up on display views but not be present at all for editing...

like image 964
Roland Tepp Avatar asked Apr 07 '11 15:04

Roland Tepp


2 Answers

You can make use of IMetadataAware interface an create attribute which will set ShowForEdit and ShowForDislay in Metadata:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TemplatesVisibilityAttribute : Attribute, IMetadataAware
{
    public bool ShowForDisplay { get; set; }

    public bool ShowForEdit { get; set; }

    public TemplatesVisibilityAttribut()
    {
        this.ShowForDisplay = true;
        this.ShowForEdit = true;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        if (metadata == null)
        {
            throw new ArgumentNullException("metadata");
        }

        metadata.ShowForDisplay = this.ShowForDisplay;
        metadata.ShowForEdit = this.ShowForEdit;
    }

}

Then you can attach it to your property like this:

public class TemplateViewModel
{
  [TemplatesVisibility(ShowForEdit = false)]
  public string ShowForDisplayProperty { get; set; }

  public string ShowAlwaysProperty { get; set; }
}

And this is all you need.

like image 59
tpeczek Avatar answered Sep 27 '22 21:09

tpeczek


You could write a custom metadata provider and set the ShowForEdit metadata property. So start with a custom attribute:

public class ShowForEditAttribute : Attribute
{
    public ShowForEditAttribute(bool show)
    {
        Show = show;
    }

    public bool Show { get; private set; }
}

then a custom model metadata provider:

public class MyModelMetadataProvider : 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 sfea = attributes.OfType<ShowForEditAttribute>().FirstOrDefault();
        if (sfea != null)
        {
            metadata.ShowForEdit = sfea.Show;
        }
        return metadata;
    }
}

then register this provider in Application_Start:

ModelMetadataProviders.Current = new MyModelMetadataProvider();

and finally decorate:

public class MyViewModel
{
    [ShowForEdit(false)]
    public string Prop1 { get; set; }

    public string Prop2 { get; set; }
}

Now if in your view you have:

@model MyViewModel

<h2>Editor</h2>
@Html.EditorForModel()

<h2>Display</h2>
@Html.DisplayForModel()

the Prop1 property won't be included in the editor template.

Remark: you could do the same with the ShowForDisplay metadata property.

like image 39
Darin Dimitrov Avatar answered Sep 27 '22 21:09

Darin Dimitrov