Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 5 custom HtmlHelper for lightweight content editing

After years of working with WebForms I recently started the transition to MVC. I'm trying to create a plugable, lightweight content editing module but I've run into some problems.

The idea is simple: create a HtmlHelper named EditableSimpleHtml that can be used in a @using... { } syntax so that the following can be achieved in a razor view:

@using (Html.EditableSimpleHtml("MyKey"))
{
    <h3>Test</h3>
    <p>
        1<br />
    </p>
}

The value between the {...} is the default value for when no content can not be found in the data storage.

I've create a HtmlHelper. Below is a simplified version:

public static IDisposable EditableSimpleHtml(this HtmlHelper helper, string key)
{
    // Get the content from the data storage using the key (I will not show the provider itself, its just a provider that will access a db)
    var provider = ContentEditing.Provider;
    string value = provider.GetValue(key);

    if (value == null)
    {
        // No value found in the data storage for the supplied key, we have to use the default value from within the @using... { } statement
        // Can I get that value here? I want to to store it initialy in the data storage

        value = "..."; // How to get html from within the @using... { }?
    }

    return new ContentEditableHtmlString(helper, value);
}

public class ContentEditableHtmlString : IDisposable
{
    private readonly HtmlHelper _helper;

    public ContentEditableHtmlString(HtmlHelper helper, string value)
    {
        _helper = helper;

        var builder = new TagBuilder("div");              
        var writer = _helper.ViewContext.Writer;
        writer.Write(builder.ToString(TagRenderMode.StartTag));
        writer.Write(value);
    }

    public void Dispose()
    {
        _helper.ViewContext.Writer.Write("</div>");
    }
}

The problem is that I can't get the (default) content from within the @using... { } statement in the HtmlHelper, or at least I don't know how. I need it in case I want to store it to the database initially.

Second problem is that the value between the @using... { } statement will always be rendered. In the case when the content can be loaded from the data storage I want the default value to be replaced with the value from the data storage.

Is there a way to achieve this or did I start of on a completely wrong path?

like image 768
Laurens Hartz Avatar asked Nov 02 '22 05:11

Laurens Hartz


1 Answers

You can not get the html within the @using{...} statement the way you are doing right now.

The closest thing you can do is use Templated Razor Delegates

public static HelperResult EditableSimpleHtml(this HtmlHelper helper, string key,
                                              Func<string, HelperResult> template)
{
    var templateResult = template(null);
    //you have your value here that you can return directly
    //or you can return HelperResult to write to the response directly
    var templateResultHtml = templateResult.ToHtmlString(); 

    return new HelperResult(writer =>
    {
        templateResult.WriteTo(writer);
    });
}

And in your view:

@Html.EditableSimpleHtml("MyKey", @<text>
                                   <h3>Test</h3>
                                   <p>@DateTime.Now</p>
                                   </text>)
like image 173
Davor Zlotrg Avatar answered Nov 15 '22 05:11

Davor Zlotrg