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

3

5

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...

Moujik answered 7/4, 2011 at 15:19 Comment(0)
B
12

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.

Barm answered 7/4, 2011 at 15:44 Comment(1)
Wonderfully elegant :) I'll be trying this out first thing tomorrow morning.Moujik
S
2

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.

Stansberry answered 7/4, 2011 at 15:24 Comment(1)
I think that the solution proposed by tpeczek is much more elegantMoujik
C
0

Can you display each of the fields you want using Html.DisplayTextbox or one of the other options? That way you can also customize the appearance and labels referring to the field.

Crissman answered 7/4, 2011 at 15:25 Comment(1)
Not really - this would completely undermine the whole point of using DisplayForModel and EditForModel methods...Moujik

© 2022 - 2024 — McMap. All rights reserved.