Sitecore Glass Mapper Get Target Object Of Lamba Exception

I have come across a problem with Sitecore Glass Mapper Model does not allow Modifications of the image fields in the sitecore edit mode (Experience Editor) and throws the following error(Glass.Mapper.Utilities.GetTargetObjectOfLamba).

at Glass.Mapper.Utilities.GetTargetObjectOfLamba[T](Expression`1 field, T model, MemberExpression& memberExpression)   at Glass.Mapper.Sc.GlassHtml.MakeEditable[T](Expression`1 field, Expression`1 standardOutput, T model, Object parameters, Context context, Database database, TextWriter writer)

The Sitecore view rendering code looks like the following.

@if (Model != null && Model.ImageLists != null && Model.ImageLists.Count() > 0)
{
       <div class="logo-collection">
@Html.Raw("<ul>");
        @foreach (var item in Model.ImageLists)
        {
          <li>@RenderImage(item, x => x, new { @class = "img-responsive" }, isEditable:  true)</li>
        }
@Html.Raw("</ul>");
    </div>
}

The supporting Model class generated by Glass Mapper for Sitecore Template looks like this

       /// LogoGrid
       /// <para></para>
       /// <para>Path: /sitecore/templates/User Defined/Feature/Media Content/Logo Grid</para>
       /// <para>ID: 3224af3f-65d8-4d40-bd17-38135c355ab0</para>
       /// </summary>
       [SitecoreType(TemplateId=ILogoGridConstants.TemplateIdString, Cachable=false)]
       public partial class LogoGrid  : GlassBase, ILogoGrid
       {
                            /// <summary>
                           /// The Image List field.
                           /// <para></para>
                            /// <para>Field Type: Multilist</para>
                           /// <para>Field ID: f0d23622-dcc9-4a6e-8868-475684324db5</para>
                           /// <para>Custom Data: type=IEnumerable<Glass.Mapper.Sc.Fields.Image></para>
                           /// </summary>
                           [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Team Development for Sitecore - GlassItem.tt", "1.0")]
                           [SitecoreField(ILogoGridConstants.ImageListsFieldName)]
                           public virtual IEnumerable<Glass.Mapper.Sc.Fields.Image> ImageLists  {get; set;}
            }

Reason

The reason for the exception is   x => x highlighted in the view. Glass Mapper will check to make sure that lambda expression is a Member Expression and will be able to retrieve the target object of the expression which is an Item in the sitecore.

So the Model LogoGrid Contains Sitecore multiList of Images and in the view, while looping through the ImageLists , RenderImage Takes item and needs to evaluate against a field in the item and not item itself( @RenderImage(item, x => x)).In other words, Glass Mapper does not expect x => x but expects x => x.Image or any field inside sitecore item and will render that field or sitecore image.

If you did not understand the above statement , I will explain in another way. If Model.ImageLists is of type IEnumerable<Glass.Mapper.Sc.Fields.Image> which will be iterated and render Image, and we use RenderImage property to render the Sitecore image in Sitecore item but here we are rendering Image in Image and hence Glass Mapper rejects that renderImage in Experience Mode. Also this problem will not be there if the multi list uses Items in it instead of Images(which are fields of item)

Solution

We can make a Sitecore multi list that contains images as data source editable by using  Glass.Mapper.Sc.Web.Mvc.BeginEditFrame (glass Mapper Helper method).

Glass Mapper Helper method need the Model which we are displaying in the Experience editor mode and the data source of the item which we wanted to edit in Sitecore Experience Mode.

The Altered Code for the Above Sitecore View Html Can look like the following

@if (Model != null && Model.ImageLists != null && Model.ImageLists.Count() > 0)
{
    var isExperienceEditorMode = Sitecore.Context.PageMode.IsExperienceEditor;
    if (isExperienceEditorMode)
    {
        using (BeginEditFrame(Model, "Image List Name" , x => x.ImageLists))
        {
            <div class="logo-collection">
                @Html.Raw("<ul>");
                @foreach (Glass.Mapper.Sc.Fields.Image item in Model.ImageLists)
                {
                    <li> <img src="@item.Src" alt="@item.Alt" /></li>
                }
                @Html.Raw("</ul>");
            </div>
        }
    }
    else
    {
        int count = 0;
        <div class="logo-collection">
            @foreach (var item in Model.ImageLists)
            {
                if (count % 3 == 0)
                {
                    @Html.Raw("<ul>");
                }
                <li>@RenderImage(item, x => x, new { @class = "img-responsive" }, isEditable: true)</li>
                if ((count + 1) % 3 == 0)
                {
                    @Html.Raw("</ul>");
                }
                count = count + 1;
            }
        </div>
    }
}

Conclusion

The Sitecore Experience Editor can edit the Items added to the Multilist in Sitecore but for Editing the Images or any custom fields that are added to Multilist, we can Use Edit Frame functionality provided by Sitecore. In our case we used Glass.Mapper.Sc.Web.Mvc.BeginEditFrame as we are using Glass Mapper ORM for creating our Models.

Note – This solution will give the ability for Sitecore content authors to edit the items (images data source in this case) in the multilist. Sitecore Experience Editor does not give the ability for content authors to change the images loading on the page directly but only can add or remove the images from the multilist in Sitecore Editor.