HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

EditHint in MVC

Describes how to use EditHint to trigger a full page refresh in edit view, when changing the value of a specific property.

When you work with Optimizely content data in MVC (model-view-controller), the view does not have to take the content data object as the view model. The received content data populates a view model that the view uses when a page loads.

When a view uses a view model instead of the content data object, the edit view is unaware of connections between the properties on the view model and the properties on the content data object, which means that you cannot update parts of the page when you change the content in the form edit view. However, you can use helper methods to show the correct data on the preview window. See example below.

Property connections

The GetEditHints extension, located in EPiServer.Web.Mvc, makes a connection between a view model property and a content data property, when you use it on the ViewData property in the controller. This method returns a class that handles two collections on the ViewData object.

AddConnection on the class uses expressions to get the view model property and the content data property, which should be connected. Use the ViewData object to set connections between properties by casting ViewData[EPiServer.Web.Mvc.ViewDataKeys.PropertyConnections to IList<EditHint>, and adding edit hints to the collection.

When you want to display the property (with a connection to a content data property) in the view, use the Html.PropertyFor extension method in the EPiServer.Web.Mvc.Html namespace, which creates a wrapping element around the property. The wrapping element has attributes with the connection to the content data property.

By default, the wrapping element is a div, but you can change the element by adding CustomTag to the list in additionalViewData (new { CustomTag = "span" }) in the overloads of PropertyFor, which contains additionalViewData.

If you cannot use a wrapping element in edit view, use the EditAttributes extension method instead, which writes the attributes for connecting the element to a property on the content data object.

You can make connections between properties directly in the view. When you use the Html.PropertyFor extension with the EditHint overload, set the ContentDataPropertyName on the EditHint object, to connect to the view data property.

When you use Html.PropertyFor, edit view automatically connects a view model property with the same name as the content data object property.

Full refresh properties

Some content data properties cannot have a one-to-one relation with a property on the view model. For example, the property ShowBanner displays a banner on the page if the property is set to true, so this property may need a full refresh of the page to render a correct preview because it can affect many things on the page.

To add a property to the full refresh list, use the GetEditHints extension method in EPiServer.Web.Mvc, which returns a class that handles two collections on the ViewData object, connections between the view model properties and the content data properties, and properties that need a full refresh.

AddFullRefreshFor on the class uses expressions to get the property from the content data object, which is added to the list. Use the ViewData object to set a property to the full refresh list by casting ViewData[EPiServer.Web.Mvc.ViewDataKeys.FullRefreshProperties] to IList<EditHint>, and adding a edit hints to the collection with the ContentDataPropertyName set to the property name.

Render the collection somewhere on the page using the Html.FullRefreshPropertiesMetaData() extension method also contains an overload that takes an array of property names. Then use the overload with the string array, but add the property names in the array for full refresh. The default method adds the properties in the ViewData collection.

Html.PropertyFor

The Html.PropertyFor methods are wrappers around Html.DisplayFor that create connections between view model properties and content data properties in edit mode. In view mode, the PropertyFor directly calls DisplayFor, but in edit view, a wrapping element is created around the property that contains a connection to a content data property (if a connection exists).

By default, the wrapping element is a div, but you can change the element by adding editepielementname to the list in additionalViewData (new { editepielementname = "span" }) in the overloads of PropertyFor, which contains additionalViewData.

Html.FullRefreshPropertiesMetaData

The Html.FullRefreshPropertiesMetaData() extensions contain a method without any parameters (default) and another that takes an array of property names. The default method adds the properties in the ViewData collection for a full refresh. The overload with the string array adds only the property names in the array for full refresh.

Html.EditAttributes

The EditAttributes extension methods add attributes to an existing element, which makes the content in the element connected to a property on the content data object in edit view, by specifying the content data object property to which the element connects.

Html.BeginEditSection

The BeginEditSection and EndEditSection extension methods work as EditAttributes by adding attributes that are needed for editing.

Use the methods when you add attributes to a property containing nested properties (such as a block) or render a property that can be nested (such as a partial view for a block). BeginEditSection ensures that only the outer property gets edit hints when there are nested properties.

When you render a block, the block property gets edit hints, while the individual properties within the block do not get edit hints.

EditHint example

The following example contains a page type, a controller, a model view, and a view.

public class EditHintSample: PageController<EditSamplePage> {
  public ActionResult Index(EditSamplePage currentPage) {
    var model = new EditSampleViewModel {
      Heading = currentPage.MyText,
        Body = currentPage.MainBody,
        SecondaryBody = currentPage.SecondaryBody,
        BannerUrl = currentPage.BannerUrl.ToString(),
        ShowBanner = currentPage.ShowBanner,
        TextBlock = currentPage.TextBlock
    };

    // Get the edit hint collections
    var editingHints = ViewData.GetEditHints<EditSampleViewModel,EditSamplePage>();

    // Adds a connection between 'Heading' in view model and 'MyText' in content data.
    editingHints.AddConnection(m => m.Heading, p => p.MyText);

    // Add the property 'ShowBanner' to the collection of properties which requires full refresh of the page.
    editingHints.AddFullRefreshFor(p => p.ShowBanner);

    return View(model);
  }
}

public class EditSampleViewModel {
  public string Heading {
    get;
    set;
  }
  public string BannerUrl {
    get;
    set;
  }
  public XhtmlString Body {
    get;
    set;
  }
  public XhtmlString SecondaryBody {
    get;
    set;
  }
  public virtual bool ShowBanner {
    get;
    set;
  }
  public virtual EditSampleBlock TextBlock {
    get;
    set;
  }
}

[ContentType]
public class EditSampleBlock: BlockData {
  public virtual string Heading {
    get;
    set;
  }
  public virtual XhtmlString Body {
    get;
    set;
  }
}

[ContentType]
public class EditSamplePage: PageData {
  public virtual string MyText {
    get;
    set;
  }
  public virtual XhtmlString MainBody {
    get;
    set;
  }
  public virtual XhtmlString SecondaryBody {
    get;
    set;
  }
  public virtual Url BannerUrl {
    get;
    set;
  }
  public virtual bool ShowBanner {
    get;
    set;
  }
  public virtual EditSampleBlock TextBlock {
    get;
    set;
  }
}

Razor view engine:

@model AlloyTemplates.Controllers.EditSampleViewModel
    @{
       Layout = null;
    }
    
    @Html.FullRefreshPropertiesMetaData()
    
    <h1 @Html.EditAttributes(m => m.Heading)>@Model.Heading</h1>
    
    @if (Model.ShowBanner)
    {
      <div @Html.EditAttributes(m => m.BannerUrl)>
        <img src="@Model.BannerUrl"/>
      </div>
    }
    
    @Html.PropertyFor(m => m.Body, new EPiServer.Web.Mvc.EditHint() { ContentDataPropertyName = "MainBody" } )
    @Html.PropertyFor(m => m.SecondaryBody)
    
    @Html.BeginEditSection("div", p => p.TextBlock)
      @Html.Partial("TextBlock", Model.TextBlock )
    @Html.EndEditSection("div")