Tuesday, August 3, 2010

Language filtered Multilist field

Recently I happened to help one of our clients to create a custom Multilist field that gives you selecting options only if item has  at least one translated version in a current content language. From content author’s point of view it makes a lot of sense. Why to give them an option that is not useful?

It’s being a while since I created a custom field that has to take into account content language selection. The main challenge for me was to retrieve that content language. I did remember that there is a property that the Content Editor (CE) sets at run-time for every field but could not recall its name. So after several minutes of browsing my code storage of all samples for all Sitecore versions, I finally found it. So, here are the properties that you need to define in your custom field if you are planning to use them afterwards:

- ItemLanauage – represents a content language selected in the CE.

- ItemID – contains the item ID the field belongs to.

- ItemVersion – contains selected item version.

- ReadOnly – indicates if field is a readonly. If it is, then it will be grayed out and not editable.

- Source – represents the source value from field definition on a data template.

- FieldID – contains the field ID.

In my example I needed only ItemLanguage property. When I put things together the code looked like this:

using Sitecore.Shell.Applications.ContentEditor;
using Sitecore.Data.Items;

namespace Sitecore.Shell.Applications.ContentEditor.CustomExtensions
{
public class LanguageFilteredMultilist : Sitecore.Shell.Applications.ContentEditor.MultilistEx
{
#region Overrides

protected override Item[] GetItems(Item current)
{
Item[] items = base.GetItems(current);

var filteredItems = items.Where(item =>
{
string lang = ItemLanguage;
if (!string.IsNullOrEmpty(lang))
{
var versions = Sitecore.Data.Managers.ItemManager.GetVersions(item, Sitecore.Data.Managers.LanguageManager.GetLanguage(lang, item.Database));
return versions.Count > 0;
}
return false;
}
);

return filteredItems.ToArray<Item>();
}

#endregion Overrides

// Content Editor sets this property. It has a content language from the Content Editor.
public string ItemLanguage
{
get;
set;
}
}
}


Simple enough isn’t it. Don’t forget to add your custom field to /App_Config/FieldTypes.config file if it’s supposed to contain references to other items. In my case it should be added since it’s a multilist. If you forget to do it, the LinkDatabase won’t update references for your field.



That’s all for now.

4 comments:

rakesh said...

Hi,
This post/Article is wonderfull,
I looking same solution for Checklist and droptree, is it possible, if so, can please send me on my email address sukanthmsc@gmail.com.

Thanks in advance,

Anonymous said...

Hi,
This post/Article is wonderfull,
I looking same solution for Checklist and droptree, is it possible, if so, can please send me on my email address sukanthmsc@gmail.com.

JonSmart said...
This comment has been removed by the author.
JonSmart said...

Just tried this in Sitecore 7.2 it no longer works because the source for MultilistEx uses calls Lookup sources directly instead of calling GetItems to build its view.

protected override void DoRender(HtmlTextWriter output)
{
Assert.ArgumentNotNull((object) output, "output");
Item current = Context.ContentDatabase.GetItem(this.ItemID, Language.Parse(this.ItemLanguage));
Item[] sources = (Item[]) null;

using (new LanguageSwitcher(this.ItemLanguage))
sources = LookupSources.GetItems(current, this.Source);

ArrayList selected;
IDictionary unselected;
this.GetSelectedItems(sources, out selected, out unselected);
this.ServerProperties["ID"] = (object) this.ID;
string str1 = string.Empty;
if (this.ReadOnly)

I am going to try a different solution but it looks like it should be just a case of overriding the ItemLanguage as it uses a ViewState not the one set externally.