Sitecore Tags Field (Tags and Autocomplete)

Tag field is using tag-it jquery plugin , where it shows suggested tags from repository in Sitecore as auto-complete, or you add new tags not available in the repository and it will be added to the repository when you save the item, Installation and Configurations are available on github: https://github.com/abarhoum/TagControl

Sitecore Marketplace :

https://marketplace.sitecore.net/en/Modules/T/Tags_Field.aspx

Video : 

Key Features :

  1. It will show you suggested tags from predefined repository for Tags in Sitecore.
  2. You can add new tag in the field, and the newly created tag will be saved in the predefined repository.
  3. It will not allow to add new tags already exist.

tagsd

This post will explain how i created this field.

Step 1: Create Project of type class library .

Step 2: Create new class and make it inherited from Sitecore.Web.UI.HtmlControls.Control:

public class TagField : Sitecore.Web.UI.HtmlControls.Control
{
#region Events
protected override void OnLoad(EventArgs e)
 {
   // code will be here ...
 }
 #endregion
}

Step 3 : Create custom field in Sitecore :

Switch to core database and navigate to /sitecore/system/Field types where you can define your custom field, i created folder called “Custom Field” and i added my field there :

customfield


Step 4 : OnLoad Event  Here I check if this event triggered from item load, or from on item-save, for this i am using Sitecore.Context.ClientPage.IsEvent, when it false that means the event triggered from item-load so i am building the control.  if it is true that means the item has been modified.

protected override void OnLoad(EventArgs e)
 {
 var literalTags = new System.Web.UI.WebControls.Literal();
 if (!Sitecore.Context.ClientPage.IsEvent)
 {
 BuildTagsControl(literalTags);
 Controls.Add(literalTags);
 }
 else
 {
 /*This line to make sure to add new tag item only when the triggered event is save, this event it will be rasied by one of the following actions:
 1) Click save from ribbon.
 2) Shortcut cltr + save.
 3) When you change the field and you go to other item without click save aciton, the dialog of "save itme changes" will appear 
 and ask you if you want to save the changes, then you click "Yes"*/
 var eventType = Sitecore.Context.ClientPage.ClientRequest.Parameters;
 var tagEntities = new List<TagEntity>();
 var jsonSerialiser = new JavaScriptSerializer();
 if (Context.Request.Form[string.Format("hdnJsonObject{0}", InputId)] != null)
 {
 var tagList = jsonSerialiser.Deserialize<List<TagEntity>>(Context.Request.Form[string.Format("hdnJsonObject{0}", InputId)]);
 if (eventType.Equals("contenteditor:save") || eventType.Contains("item:save"))
 {

var createItemTasks = new List<Task>();
 foreach (var tag in tagList)
 {
 if (tag.id == "0")
 {
 /* I created another task to create Sitecore item, the reason behind that is when you create an item here in this place sitecore will take
 you to the newly created item in the tree which is this is the default behavior for sitecore, but for this control if new tag added not already
 exists in the tag repository, then i want to create that tag in the repo and get the newly tag item id, and save it in raw value of the field.*/
 var contentDatabase = Client.ContentDatabase;
 var task = Task.Run(() => CreateItem(tag.label, contentDatabase));
 task.Wait(1);
 var item = task.Result;
 tagList.First(p => p.label.Equals(tag.label)).id = item.ID.ToString();
 }
 }
 }
 var value = jsonSerialiser.Serialize(tagList) ?? "";
 Sitecore.Context.ClientPage.Modified = (Value != value);
 if (value != null && value != Value)
 {
 Value = value;
 }
 }
 }
 base.OnLoad(e);
 }

Step 5 : BuildControl 

In this function i am reading the HTML Template for the control and using Sitecore search APIs to retrieve the tags.

void BuildTagsControl(System.Web.UI.WebControls.Literal literalTags)
 {
 try
 {
 string tagEntitiesJson = string.Empty;
 var tagEntities = new List<TagEntity>();
 StringBuilder list = new StringBuilder();
 var appDomain = AppDomain.CurrentDomain;
 var basePath = appDomain.BaseDirectory;
 var tags = TagsSearch();
 var jsonSerialiser = new JavaScriptSerializer();
 var tagsJson = jsonSerialiser.Serialize(tags);
 var path = Path.Combine(basePath, HTMLTemplatePath);
 var html = System.IO.File.ReadAllText(path);

html = html.Replace("($tags$)", tagsJson);

if (!string.IsNullOrEmpty(Value))
 {

var tagList = jsonSerialiser.Deserialize<List<TagEntity>>(Value);
 foreach (var tag in tagList)
 {
 var id = tag.id;
 if (id != "0")
 {
 ID parsedId;
 Sitecore.Data.ID.TryParse(id, out parsedId);
 if (!Sitecore.Data.ID.IsNullOrEmpty(parsedId))
 {
 var item = Client.ContentDatabase.GetItem(parsedId);
 if (item != null)
 {
 var title = !string.IsNullOrWhiteSpace(item[TitleField]) ? item[TitleField] : item.Name;
 list.Append(string.Format("<li data-id='{0}'>{1}</li>", item.ID.ToString(), title));
 tagEntities.Add(new TagEntity { id = item.ID.ToString(), label = title });
 }
 }
 }
 }
 tagEntitiesJson = jsonSerialiser.Serialize(tagEntities);
 }
 html = html.Replace("($avalilableTags$)", list.ToString());
 html = html.Replace("($jsonObject$)", string.IsNullOrEmpty(tagEntitiesJson) ? "[]" : HttpUtility.HtmlEncode(tagEntitiesJson));
 html = html.Replace("($inputid$)", InputId);
 //html = html.Replace("($controlId$)", this.InputId);
 literalTags.Text = html;
}
 catch (Exception ex)
 {
 Log.Error("TagField - BuildTagsControl method caused an unhandled exception", ex, this);
 }
 }

With this field you can create new tag, or select tag from suggestions, they come as auto-complete.

Data will come in raw values as JSON object with two properties :

 [{"id":"{0F57B1D6-F390-4FC3-A262-79966F9A1061}","label":"Tag2"},{"id":"{36EAAEDF-B8CB-42C0-B0EB-289DD4812F70}","label":"Tag3"\]

label : it has the tag name (tag title field, if there’s no field for tag item it will retrieve the item name)

Id : it will have tag item  guid

when you add new tag not exist in the repository, from the client side i am passing value for Id from the client side as “0” :

[{"id":"0","label":"New-Tag"}]

and on item save i will get all items with id=0, this means these tags are new tags, and i create those items in tags repository and retrieve the Ids and save it in the raw values with labels as JSON.

Creating new item :

I had issue here when I add new tag and save the tag in the repository, Sitecore will take you to the newly created item under tags folder, and this is the default behavior for Sitecore to fix this issue i create another .net task to execute create item as below :

var task = Task.Run(() => CreateItem(tag.label, contentDatabase));
task.Wait(1); 
var item = task.Result;

I hope you find this post helpful, If you have any additional knowledge on this subject, comments or questions, please let me know in the comments section below.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s