NCIM Sitecore Team

Just another WordPress.com site

Sitecore Custom Time Field

with 7 comments

Problem

Chantal WeijersHi Martijn, I frequently post marketing events on my website. This is not so hard to do, actually due to Sitecore this is quite easy! However, when I want to specify the start and end times I always have to provide the date as well, even when the begin and end dates are the same. Next to the fact that this is slightly annoying, it also looks misplaced and confusing. Do you have a solution for this?

Martijn van der MeerHi Chantal, I certainly do. In order to provide a solution for your problem, I will walk you through the following:

  • What is a Time Field?
  • Why a Time Field?
  • Custom Time Field Code
  • Sitecore Implementation
  • Time Field Rendering (updated)

Solution: Time Field

What is a Time Field?

A Time field is an element for displaying and selecting just the time (figure 1).

Figure 1: Custom Time field

This field type is currently not available as a standard Sitecore field. The two standard date/time elements in Sitecore which do exist are the Date field and the DateTime fields (figure 2).

Figure 2: Standard Sitecore Date and DateTime fields

Why a Time Field?

There are several occasions where a specific Time field could come in handy. For instance, the field can be used in templates for one day events or workshops when start and end times are required but not two different dates. The solution described in this post enables users to specify only what is necessary.

Custom Time Field Code

The code below implements the custom Time field. Most of the code is taken from the standard Sitecore Date field. There are a number of small adjustments made to convert it to a Time field. For instance, the Sitecore TimePicker class is used to replace the DatePicker from the original code. Complete the following steps to define the custom Time field:

  1. Create a new C# class file (e.g. TimeField.cs) in your Sitecore project.
  2. Copy the following code in it (update the namespace appropriately).
  3. Save the file and compile the project.

Now proceed with the ‘Sitecore Implementation’ section.

using System;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Shell.Applications.ContentEditor;

namespace NCIM.SitecoreTeam.Demos.CustomTypes
{
    public class TimeField : Input, IContentField
    {
        private TimePicker _picker;

        public string ItemID
        {
            get
            {
                return base.GetViewStateString("ItemID");
            }
            set
            {
                Assert.ArgumentNotNull(value, "value");
                base.SetViewStateString("ItemID", value);
            }
        }

        public string RealValue
        {
            get
            {
                return base.GetViewStateString("RealValue");
            }
            set
            {
                Assert.ArgumentNotNull(value, "value");
                base.SetViewStateString("RealValue", value);
            }
        }

        public TimeField()
        {
            this.Class = "scContentControl";
            base.Change = "#";
            base.Activation = true;
        }

        public override void HandleMessage(Message message)
        {
            Assert.ArgumentNotNull(message, "message");
            base.HandleMessage(message);
            if (message["id"] != this.ID)
            {
                return;
            }
            string name;
            if ((name = message.Name) != null)
            {
                if (name == "contentdate:today")
                {
                    this.Now();
                    return;
                }
                if (name != "contentdate:clear")
                {
                    return;
                }
                this.ClearField();
            }
        }

        public string GetValue()
        {
            if (this._picker == null)
            {
                return this.RealValue;
            }
            return this._picker.Value;
        }

        public void SetValue(string value)
        {
            Assert.ArgumentNotNull(value, "value");
            this.RealValue = value;
            if (this._picker != null)
            {
                this._picker.Value = value;
            }
        }

        protected override Item GetItem()
        {
            return Client.ContentDatabase.GetItem(this.ItemID);
        }

        protected override bool LoadPostData(string value)
        {
            if (base.LoadPostData(value))
            {
                this._picker.Value = (value ?? string.Empty);
                return true;
            }
            return false;
        }

        protected override void OnInit(EventArgs e)
        {
            base.SetViewStateBool("Showtime", true);
            this._picker = new TimePicker();
            this._picker.ID = this.ID + "_picker";
            this.Controls.Add(this._picker);
            if (!string.IsNullOrEmpty(this.RealValue))
            {
                this._picker.Value = this.RealValue;
            }
            this._picker.OnChanged += delegate
            {
                this.SetModified();
            };
            this._picker.Disabled = this.Disabled;
            base.OnInit(e);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            base.ServerProperties["Value"] = base.ServerProperties["Value"];
            base.ServerProperties["RealValue"] = base.ServerProperties["RealValue"];
        }

        protected override void SetModified()
        {
            base.SetModified();
            if (base.TrackModified)
            {
                Sitecore.Context.ClientPage.Modified = true;
            }
        }

        private void ClearField()
        {
            this.SetRealValue(string.Empty);
        }

        private void SetRealValue(string realvalue)
        {
            if (realvalue != this.RealValue)
            {
                this.SetModified();
            }
            this.RealValue = realvalue;
            this._picker.Value = realvalue;
        }

        private void Now()
        {
            this.SetRealValue(DateUtil.IsoNowTime);
        }
    }
}

Sitecore Implementation

Figure 3: Sitecore system content tree (core database)

Make sure the project containing the TimeField type is compiled and available in the \bin folder of your Sitecore solution. Then follow these steps within Sitecore.

  1. Open Sitecore in Desktop mode.
  2. Open the Core database. (in the lower right corner of the screen to change database.)
  3. Open the Content Editor.
  4. Navigate to Sitecore/System/Field Types/Simple Types. In this folder all the simple types for the Sitecore templates are listed.
  5. Duplicate the Date item and rename it to Time (figure 3).
  6. Open the Time item.
  7. Optional: Change the icon for the item to something more specific for time (e.g. People/32×32/clock.png).
  8. Enter the name of the dll that contains the TimeField type (without the .dll extension) in the Assembly field (example: NCIM.SitecoreTeam.Demos, figure 4).
  9. Enter the the namespace + name of the TimeField class in the Class field (example: NCIM.SitecoreTeam.Demos.CustomTypes.TimeField).
  10. Empty the Control field.
  11. Save the item.
  12. Expand the Time item and open the Menu folder.
  13. Select the Today item and rename it to Now.
  14. Open the Now item and change the value of the Display name field to Now.
  15. Save the item.
  16. Delete the WebEdit Buttons folder underneath the Menu folder. This enables the display of a calendar control in Preview/Edit mode and is useless for the Time field.
  17. Save the item.

Figure 4: Time type details

The Time type should now be available as a simple type in Sitecore templates as shown in figure 5.

Figure 5: Time available as simple type in a template

An example of an event item with Start and End time fields is shown in figure 6.

Figure 6: Sample event showing Start and End times.

Update: Time Field Rendering

I received a question about extending this solution to enable a Time field rendering in weblayouts and controls using markup such as:

<sc:Time runat="server" ... />

First I looked into the implementation of the Sitecore Date field  (Sitecore.Web.UI.WebControls.Date in Sitecore.Kernel) and created a Time class based on that. Follow these steps to add a Time class to your solution:

  1. Create a new C# class file (e.g. Time.cs) in your Sitecore project.
  2. Copy the following code in it (update the namespace appropriately).
  3. Save the file and compile the project.
using Sitecore.Collections;
using Sitecore.Diagnostics;
using Sitecore.Web.UI.WebControls;

namespace NCIM.SitecoreTeam.Demos.CustomTypes
{
   public class Time : FieldControl
   {
      public string Format { get; set; }

      protected override void PopulateParameters(SafeDictionary<string> parameters)
      {
         Assert.ArgumentNotNull(parameters, "parameters");
         base.PopulateParameters(parameters);
         if (string.IsNullOrEmpty(Format))
            return;
         parameters.Add("format", Format);
      }
   }
}

In order to use the sc tag prefix either register the namespace in the control where you want to use the Time field or register the namespace in the web.config:

<%@ Register TagPrefix="sc" Namespace="NCIM.SitecoreTeam.Demos.CustomTypes" Assembly="NCIM.SitecoreTeam.Demos" %>

Now the sc:Time rendering can be used, for instance when using the SampleEvent item which has a Start time field (have a look again at figure 6):

<sc:Time runat="server" ID="StartTimeField" Field="Start time" />
Advertisements

Written by marcduiker

August 6, 2012 at 12:05 pm

Posted in Sitecore

Tagged with , , ,

7 Responses

Subscribe to comments with RSS.

  1. This was an elegant solution to my problem, and saved me a bunch of time, thanks!

    Jon Upchurch

    April 11, 2013 at 8:12 pm

  2. […] Time Field – Allow users to select a time. Note that this differs from the standard Sitecore DateTime field because it is a time field on its own without the date field. […]

  3. Thanks mate, saved time!

    Maksym

    February 26, 2014 at 11:36 pm

  4. I couldn’t get this fully working; in the content editor, on Sitecore 7.2, only a single-line text field is displayed. Any ideas? Thanks.

    Jeff

    July 17, 2014 at 8:29 pm

    • I was able to get this working finally. The problem was that the initialization sequence of events was not allowing the time picker to be added to the controls list. I solved this by moving the bulk of the OnInit method’s logic to a method named Initialize, making sure with a boolean variable that the initialization code would only be called once, and adding “this.Page.Init += Initialize;” to the constructor. Works fine, thank you! 🙂

      Jeff Varszegi

      July 18, 2014 at 3:29 pm

  5. Thank you for this. Extremely helpful and easy. One question. How can I modify this to display the list of times to ‘Hours’ only. No half hour options.

    Scott Noring

    August 5, 2014 at 2:12 pm

  6. […] developer struggled with the problem of implementing a time field and many developers found this article which provides good solution to the problem. The field works well, uses Sitecore built-in […]


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 )

Connecting to %s

%d bloggers like this: