简体   繁体   中英

Dynamic EditorFor using template from Model

The project is currently MVC3 but could be upgraded if required.

I'm trying to get a content editor for a simple cms improved. At the moment we use

@Html.EditorFor(model=>model.Content) //Content is a List<EditableContent>

EditableContent has a (brand new) property of string EditorView. The idea is this will name suitable editors for particular items of content.

What I want to do is use my default EditableContent template if EditorView is null, otherwise use the EditorView as the named template. I'm aware of the overload for EditorFor that takes a template, but that's going to use the same template for each item of content, but that's not what I want.

I did try taking my default template and basically doing

//Shared/EditorTemplates/EditableContent.cshtml
@model Website.Areas.Admin.EditableContent

@if (!string.IsNullOrWhiteSpace(Model.EditorView))
{
<text>
    @Model.EditorView
    @Html.EditorForModel(Model.EditorView)
</text>
}
else
{
  //Original template
}

Weirdly in this case, the view is located (I have a slightly custom view engine which appears to locate the view correctly). The name of the view (via @Model.EditorView ) is emitted to the page, but @Html.EditorForModel() doesn't produce anything.

Any ideas how I can use a custom template per item using EditorFor or similar ?

Interface

interface IEditableContent
{
    public virtual DatabaseContext.Content Content { get; set; }
}

Implementation

class SomeTypeEditableContent : IEditableContent
{
    public SomeTypeEditableContent(DatabaseContext.Content c)
    {
        Content = c;
    }
}

Service (Repository or Controller action)

List<IEditableContent> lEditableContent = new List<IEditableContent>();
foreach(var c in db.Contents)
{
    switch (c.EditorView)
    {
    case "SomeType":
        lEditableContent.Add(new SomeTypeEditableContent(c));
        break;
    default:
        lEditableContent.Add(new DefaultEditableContent(c));
        break;
    }
}

View

@Html.EditorFor(model=>model.ListContent) //List<IEditableContent>

Editable SomeType Template

@model SomeTypeEditableContent
//Display this as a editable string

Default Editable Content Template

@model IEditableContent
//Use default display

I'm sorry I do not have the time to test it. Let me know how it goes and i'll edit / delete this answer if it does not. I would have posted this as a comment but I needed anotation and formating. But at least it gives you an idea of what I had in mind.

-Edit-

The point of this exemple is to show you that MVC framework should be able to determine the proper template for a implementated interface even if simply providing the object typed as the interface. It will use refelction (i believe?) to find the highest class definition then look for the template.

-Edit 2 (based off comments)-

Changed the exemple to match new specifications

It seems weird that you are trying to override the editor template from a view that is already overriding the template. I'm not sure if that will work (it might, but I have never tried so I don't know). I've already added a couple comments to your question above.

If it turns out that trying to specify templates from the EditorTemplates folder doesn't work, which would be understandable, I think you could achieve what you want by introducing a custom EditorForModel() override. You can use David Ebbo's Razor Generator VS extension to define a razor helper that will be usable across your entire project.

/// /Views/Helpers/AndiEditorForExtensions.cshtml
@helper AndiEditorFor(HtmlHelper html, Website.Areas.Admin.EditableContent model) {
    if (!string.IsNullOrWhiteSpace(Model.EditorView)) {
    <text>
        @Model.EditorView
        @Html.EditorForModel(Model.EditorView)
    </text>
    }
    else {
        // Call @Html.EditorFor(), which will use the default editor template (i.e., NOT your custom one defined in the database)
        @Html.EditorFor(model) 
    }
}

Then from your normal code that loads the EditableContent items from the db and displays them, call your custom extension:

@Html.AndiEditorFor(model)

UPDATE:

A better option might be to skip the Razor Generator altogether. Just define a custom HtmlHelper, mimicking the EditorExtensions methods . Add a similar if/else to handle Model.EditorView having a value or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM