Reputation: 1421
I need to extend Html.Editor()
so base on some attributes in model to generate HTML. Example:
public class Person
{
public string Name { get; set; }
[DisplayFor(Role.Admin)]
public string Surname { get; set; }
}
In this case the generated HTML will not be displayed in View
if user is different from admin.
Upvotes: 1
Views: 1658
Reputation: 1038800
Here's a sample implementation. Let's assume that you have defined the following attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class DisplayForAttribute : Attribute
{
public DisplayForAttribute(string role)
{
Role = role;
}
public string Role { get; private set; }
}
Next you could write a custom metadata provider which will use this attribute:
public class MyMetadataProvider : 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 displayFor = attributes.OfType<DisplayForAttribute>().FirstOrDefault();
if (displayFor != null)
{
metadata.AdditionalValues.Add("RequiredRole", displayFor.Role);
}
return metadata;
}
}
which will be registered in Application_Start
:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new MyMetadataProvider();
}
and the last part is to write a custom editor template for the String type (~/Views/Shared/EditorTemplates/String.cshtml
):
@{
var visible = false;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("RequiredRole"))
{
var role = (string)ViewData.ModelMetadata.AdditionalValues["RequiredRole"];
visible = User.IsInRole(role);
}
}
@if (visible)
{
@Html.TextBox(
"",
ViewData.TemplateInfo.FormattedModelValue,
new { @class = "text-box single-line" }
)
}
and lastly to use the attribute:
public class MyViewModel
{
[DisplayFor("Admin")]
public string Name { get; set; }
}
and in the view:
@using (Html.BeginForm())
{
@Html.EditorFor(model => model.Name)
<input type="submit" value="OK" />
}
Obviously this covers only the string editor template but the example could be easily extended to the other default templates including display templates as well.
Upvotes: 2
Reputation: 351
I have the same stuff in my project, but the code is at work.
I wrote an extension method for ModelMetadata
or / and PropertyInfo
public static bool IsVisibleForRole( this PropertyInfo property, User c);
In my Object.ascx:
for ( var field in fields ) {
if(!field.IsVisibleForRole(this.CurrentUser())) continue;
//...
}
Though, in your case, you might not skip the field, but insert a <input type="hidden">
instead. But this might be security issue. For details, have look at: http://www.codethinked.com/aspnet-mvc-think-before-you-bind
Upvotes: 0