8

I am working on an inherited project that was built with minimal support for editing with the Experience Editor (Sitecore 8.2.4). In particular, I need to retrofit EditFrames (documentation link).

For some background, the project uses the Sitecore.React project as its view engine (razor is replaced by React JS), so existing razor helpers for EditFrame rendering were not available.

How can I programmatically supply/build EditFrames within the MVC C# code?

8

I was able to supply the view layer with EditFrame HTML by adding the opening and closing HTML markup into my MVC Model.

HTMLHelper

Step 1: Obtain access to HtmlHelper using your current context Controller and a "Fake View".

public static HtmlHelper GetHtmlHelper(this Controller controller)
{
    StringBuilder sb = new StringBuilder();
    HtmlTextWriter htw = new HtmlTextWriter(new System.IO.StringWriter(sb, System.Globalization.CultureInfo.InvariantCulture));
    var viewContext = new ViewContext(controller.ControllerContext, new FakeView(), controller.ViewData, controller.TempData, htw);
    return new HtmlHelper(viewContext, new ViewPage());
}

An example of using fake view can be found on this question.

EditFrame Rendering

Step 2: Use the EditFrameRendering class (similar to that in Habitat) to obtain the opening and closing HTML markup.

public void SetEditDatasourceEditFrame(IComponentModelBase model, Controller controller)
{
    var htmlHelper = controller.GetHtmlHelper();
    EditFrameRendering editFrame = new EditFrameRendering(htmlHelper.ViewContext.Writer, model.DataSourcePath, _editFrameLocation, "Edit Component", string.Empty, string.Empty, null);
    model.EditDatasourceStart = editFrame.EditFrameStart();
    model.EditDatasourceEnd = editFrame.EditFrameEnd();
}

EditFrameRendering.cs

Note the modification to EditFrameRendering.cs from the Habitat project to support the code above.

public string EditFrameStart()
{
    StringWriter stringWriter = new StringWriter();
    // Put HtmlTextWriter in using block because it needs to call Dispose.
    using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
    {
        this._editFrame.RenderFirstPart(writer);
    }
    // Return the result.
    return stringWriter.ToString();
}

public string EditFrameEnd()
{
    StringWriter stringWriter = new StringWriter();
    // Put HtmlTextWriter in using block because it needs to call Dispose.
    using (HtmlTextWriter writer = new HtmlTextWriter(stringWriter))
    {
        this._editFrame.RenderLastPart(writer);
    }
    // Return the result.
    return stringWriter.ToString();
}

View Layer

In your view layer access the model, writing out the start and end HTML. Adding any content to go within the edit frame between the tags.

Example React View:

const ReactDOMServer = require('react-dom/server');

...

editFrameMarkup() {
    const content = (<div>My Edit Frame</div>);
    return (<li><div dangerouslySetInnerHTML={this.createMarkup(this.props.data.EditDatasourceStart, content, this.props.data.EditDatasourceEnd)} /></li>);
},

createMarkup(open, content, close) {
    const htmlString = ReactDOMServer.renderToStaticMarkup(content);
    const wrapper = open + htmlString + close;
    return { __html: wrapper };
}

The above markup was taken from a reusable react component used across all renderings. The model was passed to this react component as a property called data.

The Github example is available here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.