1

If i have a ViewModel like this:

public class SignupViewModel
{
   [Required]
   [DisplayName("Email:")]
   public string EmailAddress { get; set; }   
}

And use EditorFor to render out the form fields:

@Html.EditorFor(model => model.EmailAddress )

It will render <input type="text">. Cool.

But in this particular scenario, i have already retrieved Email from a different source, and i wish to pre-fill the form with this data, and show a label instead of a textbox (as i don't want them to change their email - don't worry about why).

I know i can use [UIHint], but can i do that programatically from the controller?

E.g:

var model = new SignupViewModel();
model.EmailAddress = GetFromMysterySource(); // How do i set a UIHint?

What's the best way to approach this? Should i use a seperate ViewModel altogether, which could mean changing my View from being strongly-typed to being dynamic, or should i not use EditorFor, or should i use a custom editor template?

Suggestions/advise would be greatly appreciated.

RPM1984
  • 72,246
  • 58
  • 225
  • 350

1 Answers1

2

You can't apply an attribute at runtime. My suggestion would be to build a bit of logic into your view to control how the view renders the data. You may need to augment your model to indicate to the view which display to choose.

  @if (Model.EmailAddressIsFixed)
  {
     @Html.DisplayFor( m => m.EmailAddress )
     @Html.HiddenFor( m => m.EmailAddress ) // only if you need it to post back
  }
  else
  {
     @Html.EditorFor( m => m.EmailAddress )
  }

If you are doing this in more than one place, then a custom editor template doing the same thing would probably be in order.

  @Html.EditorFor( m => m.EmailAddress, 
                   "FixedAddressTemplate",
                   new { Fixed = Model.EmailAddressIsFixed } )
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • How would i do it with an editor template though? As there is no relationship between `EmailAddressIsFixed` and `EmailAddress`. I could create a nested viewmodel, but then i won't be able to use data attributes on the parent model level (e.g `[Required]`). – RPM1984 Apr 05 '11 at 03:32
  • @RPM - you can pass extra data to the editor template. `@Html.EditorFor( m => m.EmailAddress, new { Fixed = Model.EmailAddressIsFixed } )` – tvanfosson Apr 05 '11 at 13:01
  • @tvanfossen - still can't put data attributes on it. Where do i put the `[Required]` attribute? As it's no longer a field e.g `public string EmailAddress { get; set; }`, it's a class. And i can't put the attribute on the fields in the inner class, because then it's not re-usable. – RPM1984 Apr 06 '11 at 03:34
  • @RPM -- how about not using a nested model and providing the template name in the helper method? – tvanfosson Apr 06 '11 at 12:15
  • Yep, that's a good idea. Ok, you've got me on the right track. Accepted, thanks! – RPM1984 Apr 06 '11 at 23:24
  • Hmm 'You can't apply an attribute at runtime'. Afaik that is possible. Have a look here http://dotnetslackers.com/articles/aspnet/Customizing-ASP-NET-MVC-2-Metadata-and-Validation.aspx – TweeZz Jun 25 '12 at 06:42
  • @TweeZz - strictly speaking that doesn't apply the attribute to the class, but rather modifies the metadata for the model supplied to the view. Normally the metadata is filled from the attributes, but using a custom metadata provider allows you to augment it. There are other hooks in MVC that allow you to set up global filters as well that act in the same way as attributes, but that's still not "applying the attribute to the class at runtime." It's taking advantage of the framework-supplied filter pipeline. It would be an alternative to this method, though. – tvanfosson Jun 25 '12 at 12:36