For the code:
strMenuText.Append(RenderLink(mainlinkitem,
x => x.NavigationItem.Url.StringToLink(),
isEditable: true,
contents: mainlinkitem.NavigationTitle));
Here mainlinkitem
is Navigation object for interface created for data template.
I am using interfaces in this case and castle windsor creates dynamic proxy objects for this.
Things work ok until I try to use Page editor mode and below error shows up from glass mapper api.
Expression doesn't evaluate to a member x.NavigationItem.Url.StringToLink() at Glass.Mapper.Sc.GlassHtml.MakeEditable[T](Expression
1 field, Expression
1 standardOutput, T model, String parameters, Context context, Database database, TextWriter writer)
Note: StringToLink is extension method for converting external url in string
form to Glass mapper Glass.Mapper.Sc.Fields.Link
type.
public static Link StringToLink(this string urlvalue)
{
Link itemLink = new Link();
itemLink.Url = urlvalue;
return itemLink;
}
UPDATE
Code for menu user control:
public partial class MenuControl : GlassUserControl<INavigationFolder>
{
protected override void GetModel()
{
base.GetModel();
SiteLevelSettings siteSettings = SitecoreContext.GetItem<SiteLevelSettings>(Guid.Parse("Some GUID"));
Model = siteSettings.HeaderMenuFolder;
}
protected void Page_Load()
{
if (!Page.IsPostBack)
{
LoadMenu();
}
}
private void LoadMenu()
{
StringBuilder strMenuText = new StringBuilder();
foreach (INavigationLink mainlinkitem in Model.ChildLinks)
{
if (CanRead(mainlinkitem))
{
strMenuText.Append("<td class='menu-item'>");
if (mainlinkitem.ChildLinks != null && mainlinkitem.ChildLinks.Count() > 0)
{
strMenuText.Append("<ul>");
foreach (INavigationLink linkitem in mainlinkitem.ChildLinks)
{
if (CanRead(linkitem))
{
strMenuText.Append("<li>");
if (linkitem.NavigationItem != null)
{
strMenuText.Append(RenderLink(linkitem, x => x.NavigationItem.Url.StringToLink(), isEditable: false, contents: linkitem.NavigationTitle));
}
else if (linkitem.NavigationGeneralLink != null)
{
strMenuText.Append(RenderLink(linkitem, x => x.NavigationGeneralLink, isEditable: false, contents: linkitem.NavigationTitle));
}
strMenuText.Append("</li>");
}
}
strMenuText.Append("</ul>");
}
strMenuText.Append("<div class='nav-divider'>");
if (mainlinkitem.NavigationItem != null)
{
strMenuText.Append(RenderLink(mainlinkitem, x => x.NavigationItem.Url.StringToLink(), isEditable: false, contents: mainlinkitem.NavigationTitle));
}
else if (mainlinkitem.NavigationGeneralLink != null)
{
strMenuText.Append(RenderLink(mainlinkitem, x => x.NavigationGeneralLink, isEditable: true, contents: mainlinkitem.NavigationTitle));
}
strMenuText.Append("</div></td>");
}
}
ltrMenu.Text = strMenuText.ToString();
}
private bool CanRead(IItem mainlinkitem)
{
var ItemId = mainlinkitem.TemplateId;
var ItemIDObj = new Sitecore.Data.ID(ItemId);
var contentdatabase = Sitecore.Context.Database;
var item = contentdatabase.GetItem(ItemIDObj);
return item.Access.CanRead();
}
}
Navigation Folder interface for glass mapper:
[SitecoreType(TemplateId = "{Some GUID}")]
public interface INavigationFolder : IItem
{
[SitecoreChildren(IsLazy = false)]
IEnumerable<INavigationLink> ChildLinks { get; set; }
}
Navigation Link interface for glass mapper:
[SitecoreType(TemplateId = "{Some GUID}")]
public interface INavigationLink : IItem
{
[SitecoreField(FieldId = "{Some GUID}")]
string NavigationTitle { get; set; }
[SitecoreField(FieldId = "{Some GUID}")]
IItem NavigationItem { get; set; }
[SitecoreField(FieldId = "{Some GUID}")]
Link NavigationGeneralLink { get; set; }
[SitecoreField(FieldId = "{Some GUID}")]
string ShortDescription { get; set; }
[SitecoreChildren(IsLazy = false)]
IEnumerable<INavigationLink> ChildLinks { get; set; }
}
Note: This will code will generate menu similar to sitecore site
UPDATE
Url property in interface IItem
is defined as follows:
[SitecoreType(TemplateId = "{Some GUID}")]
public interface IItem
{
[SitecoreId()]
Guid ID { get; }
[SitecoreInfo(Type = SitecoreInfoType.Language)]
Language Language { get; }
[SitecoreInfo(Type = SitecoreInfoType.Version)]
int Version { get; }
[SitecoreInfo(Type = SitecoreInfoType.Url)]
string Url { get; }
[SitecoreInfo(Type = SitecoreInfoType.TemplateId)]
Guid TemplateId { get; }
[SitecoreInfo(Type = SitecoreInfoType.Key)]
string Key { get; }
}
The second expression in the RenderLink methods should resolve to the property that represents the field you want to be editable in the Page Editor, e.g.:
When you add the additional method call to the end of the expression Glass.Mapper cannot evaluate which field to make editable correctly.
Instead if you want to do something like this you should probably use an if statement to switch between the two renderings:
However I haven't tested this, instead you should update your property to the Link field type and it will automatically map it:
You can then update the menu code to: