For not so long ago I saw the Content Editor as the only true tool that the editors should use for administering websites.
But then I had a revelation – the DMS – and the Page Editor showed me the way.
The Page Editor feels really nice and it’s so easy to work with. It has some nice controls like the sc:text, sc:Image and sc:link. But where are the others? I mean the sitecore dropdown control or something simple as the checkbox control…
First I thought it must be easy to implement. I could always use the sc:EditFrame but then I realized it’s just another way of using the Content Editor, it’s not good enough. If you are using the Page Editor then you should go all the way.
So I started to analyze how Sitecore did in the Page Editor and I found the magic ingredient, the javascript method: Sitecore.WebEdit.setFieldValue
This little baby creates a hidden field which the Page Editor reads when a “Save” or “Save/Close” button is clicked.
The parameters for the method are:
- Sitecore.ItemUri
- FieldId
- The actual value
The Sitecore.ItemUri needs following parameters:
- Item Id
- LanguageVersion
- Revision.
So now I could finally start doing some cool stuff.
In this case I have a page that presents a simple registration form. I wanted to give the editors the choice to decide if the text fields needs to be validated.
The item itself contains some labels and checkboxes (for the validation).
I was thinking of presenting the validation choices as checkboxes in the Page Editor , but unfortunately the Page Editor seems to interfere with checkbox control (html). I couldn’t get it to work so instead I used a select box containing “true/1” and “false/0” values.
The code for the validation “checkboxes” in the Page Editor:
<span runat="server" visible="<%# Sitecore.Context.PageMode.IsPageEditorEditing %>"> <span style="font-size: x-small">Should field be validated?</span> <select onchange="var itemUri = new Sitecore.ItemUri( '<%# this.GetDataSourceOrContextItem().ID.ToShortID() %>', '<%# this.GetDataSourceOrContextItem().Language.ToString() %>', '<%# this.GetDataSourceOrContextItem().Version.ToString() %>', '<%# new ID(this.GetDataSourceOrContextItem()[FieldIDs.Revision]).ToShortID() %>'); Sitecore.WebEdit.setFieldValue( itemUri, '<%# Sandbox.Newsletter.Constants.FieldIDs.RegistrationForm.RegistrationFormFirstNameShouldBeValidated.ToShortID() %>', this.options[this.selectedIndex].value); "> <option value="1" <%# this.GetDataSourceOrContextItem().GetCheckBoxValue(Sandbox.Newsletter.Constants.FieldIDs.RegistrationForm.RegistrationFormFirstNameShouldBeValidated) ? "selected" : string.Empty %>>Yes</option> <option value="0" <%# !this.GetDataSourceOrContextItem().GetCheckBoxValue(Sandbox.Newsletter.Constants.FieldIDs.RegistrationForm.RegistrationFormFirstNameShouldBeValidated) ? "selected" : string.Empty %>>No</option> </select> </span>
If you are wondering what the GetDataSourceOrContextItem is? It’s something I used from Brian Pedersen’s blog, http://briancaos.wordpress.com/2013/09/13/avoid-the-use-of-sitecore-context-item/.
(Method: GetCheckboxValue is also an extension method)
Everything worked and I was a happy man, but then I realized that I have to repeat this for every input field in the registration form. Not pretty at all…
So I looked how Sitecore did with their “sc:controls” and finally I came up with a control which will look like this when used in the Page Editor:
<%@ Register TagPrefix="mycontrol" Namespace="Sandbox.Framework.Controls.PageEditor" Assembly="Sandbox.Framework.Controls" %> <span runat="server" visible="<%# Sitecore.Context.PageMode.IsPageEditorEditing %>"> <span style="font-size: x-small">Should field be validated?</span> <mycontrol:PageEditorCheckboxControl TrueText="Yes" FalseText="No" DataSource="<%# this.GetDataSourceOrContextItem().ID %>" Field="<%# Sandbox.Newsletter.Constants.FieldIDs.RegistrationForm.RegistrationFormFirstNameShouldBeValidated %>" runat="server" /> </span>
And here is the complete code for the customized control:
public class PageEditorCheckboxControl : FieldControl { private readonly SafeDictionary<string> _parameters = new SafeDictionary<string>(); public string TrueText { get; set; } public string FalseText { get; set; } protected override void DoRender(HtmlTextWriter output) { if (string.IsNullOrEmpty(Field)) throw new InvalidOperationException("Field property is required. All field web controls require the field name to be set."); FieldRenderer fieldRenderer = new FieldRenderer { Parameters = GetParameters(), DisableWebEditing = DisableWebEditing }; StringBuilder stringBuilderOnChange = new StringBuilder(); StringBuilder stringBuilderSelect = new StringBuilder(); stringBuilderOnChange.AppendFormat(@"var itemUri = new Sitecore.ItemUri('{0}','{1}','{2}','{3}');", GetItem().ID.ToShortID(), GetItem().Language, GetItem().Version, new ID(GetItem()[FieldIDs.Revision]).ToShortID()); stringBuilderOnChange.AppendFormat(@"Sitecore.WebEdit.setFieldValue(itemUri,'{0}',this.options[this.selectedIndex].value);", Field); stringBuilderSelect.AppendFormat(@"<select onchange=""{0}"" >", stringBuilderOnChange.ToString()); stringBuilderSelect.AppendLine(); stringBuilderSelect.AppendFormat(@"<option value='0' {0} >{1}</option>", GetItem()[Field] == "0" ? "selected" : string.Empty, FalseText); stringBuilderSelect.AppendFormat(@"<option value='1' {0} >{1}</option>", GetItem()[Field] == "1" ? "selected" : string.Empty, TrueText); stringBuilderSelect.AppendLine(); stringBuilderSelect.Append("</select>"); output.Write(stringBuilderSelect.ToString()); } protected override Item GetItem() { if (this.Item != null) return this.Item; return !string.IsNullOrWhiteSpace(this.DataSource) ? Sitecore.Context.Item.Database.GetItem(this.DataSource) : base.GetItem(); } private string GetParameters() { PopulateParameters(_parameters); return WebUtil.BuildQueryString(_parameters, false); } }
That’s all for now folks 🙂
Hi Göran,
I have been trying to implement this example but i keep running into problems when I am trying to save. When I save it throws a “System.ArgumentOutOfRangeException” with the title:
“Index and length must refer to a location within the string. Parameter name: length”
I’m not sure where I’m going wrong since what I’m trying to do is exactly the same as you.
Hope to hear from you soon,
Vincent Kong
LikeLike
Hello Vincent
Thank you for testing my stuff 🙂
Did you try the dirty version first, not use the “PageEditorCheckboxControl”?
Please email me your code and I will take a look at it, my email is: goranhalvarsson@gmail.com
/Göran
LikeLike
`stringBuilderOnChange.AppendFormat(@”Sitecore.WebEdit.setFieldValue(itemUri,'{0}’,this.options[this.selectedIndex].value);”, Field);`
`Field` needs to be the FieldID not the field name – I replaced with `GetItem().Fields[Field].ID.ToShortID()` and all is now working correctly.
LikeLiked by 1 person
Hi
Thanks for reading the post and testing my code 🙂
Well pointed out. The constant(Sandbox.Newsletter.Constants.Fields.RegistrationForm.RegistrationFormFirstNameShouldBeValidated) I’m sending to the control, mycontrol:PageEditorCheckboxControl, is a field Id. Unfortunately it’s not clear enough. I will change the constant to be more understandable.
LikeLike