WFFM Session Aware Single-Line Text Field

Recently we faced an issue where a value of certain Single-Line Text Field in Web Forms For Marketers had to be populated by a variable in the session. The problem is that WFFM only supports query string parameters for populating fields. The good thing is that WFFM is extremely easy to extend :). The tricky part here is that with the recent versions of Sitecore the field needs to be created for MVC as well (WFFM 2.4+ and Sitecore 7+). In addition to the field there will be two boolean values which will control if the field is going to be hidden (display:none;) and if the session variable should be removed after the field is populated (Which is easily doable with decorators).

So all in all building a session aware Single-Line Text Field requires 2 classes – 1 Main where our properties will be for WebForms and 1 for MVC. It is also required to register the field with WFFM which means creating a custom Field Item.

First goes the main class. It should have 3 Properties:

  1. SessionKey for storing the key which should be captured.
  2. DeleteKeyAfterCapture – flag which indicates if the key needs to be removed from the session after the value is already used.
  3. IsHidden – flag which indicates if the field needs to be hidden or displayed.

In WFFM the type of the field which will be displayed in the form designer is controlled by the VisualFieldType decorator. The problem here is that the Boolean Field type (not counting the tag field for Engagement Analytics :)) is represented by <select> element with two options – Yes and No. In the code there is a workaround for this problem taken from the DropList field. Here is the code for the class:

using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web;
using Sitecore.Form.Core.Attributes;
using Sitecore.Form.Web.UI.Controls;

namespace WFFM.Custom.Fields
{
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    public class SingleLineSessionTextField : SingleLineText
    {
        [VisualCategory("Session")]
        [VisualProperty("Session Key", 100), DefaultValue("")]
        public string SessionKey { get; set; }

        private bool _deleteKeyAfterCapture = true;

        [DefaultValue("Yes")]
        [VisualCategory("Session")]
        [VisualFieldType(typeof (Sitecore.Form.Core.Visual.BooleanField))]
        [VisualProperty("Delete Key After Capture?", 200)]
        public string DeleteKeyAfterCapture
        {
            get
            {
                return _deleteKeyAfterCapture ? "Yes" : "No";
            }
            set
            {
                _deleteKeyAfterCapture = value == "Yes";
            }
        }

        private bool _isHidden = true;

        [VisualCategory("Session")]
        [VisualFieldType(typeof (Sitecore.Form.Core.Visual.BooleanField))]
        [VisualProperty("Is Hidden?", 300), DefaultValue("Yes")]
        public string IsHidden
        {
            get
            {
                return _isHidden ? "Yes" : "No";
            }
            set
            {
                _isHidden = value == "Yes";
            }
        }

        protected override void OnLoad(System.EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(SessionKey))
            {
                if (HttpContext.Current != null && HttpContext.Current.Session[SessionKey] != null)
                {
                    Text = HttpContext.Current.Session[SessionKey].ToString();

                    if (_deleteKeyAfterCapture)
                    {
                        HttpContext.Current.Session.Remove(SessionKey);
                    }

                }
            }

            if (_isHidden)
            {
                Attributes["style"] = "display:none";
            }
        }
    }
}

The logic is located in the OnLoad method. There is basically a check for the Session Key and the field Text is prepopulated from the Session if the key exists – nothing complex 🙂

Second goes the class for the MVC field which is only required if the field is going to be used in MVCForm Rendering.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using Sitecore.Data.Items;

namespace WFFM.Custom.MVC.Fields
{
    public class SingleLineSessionTextField : Sitecore.Forms.Mvc.Models.Fields.SingleLineTextField
    {
        public string SessionKey { get; set; }

        [DataType(DataType.Text)]
        public override object Value { get; set; }

        public SingleLineSessionTextField(Item item)
            : base(item)
        {
            Initialize();
        }

        private void Initialize()
        {
            KeyValuePair<string, string> deleteKeyAfterCapture =
                ParametersDictionary.FirstOrDefault(x => x.Key.ToUpper() == "DELETEKEYAFTERCAPTURE");

            KeyValuePair<string, string> isHidden =
                ParametersDictionary.FirstOrDefault(x => x.Key.ToUpper() == "ISHIDDEN");

            if (!string.IsNullOrWhiteSpace(SessionKey))
            {
                if (HttpContext.Current != null && HttpContext.Current.Session[SessionKey] != null)
                {
                    Value = HttpContext.Current.Session[SessionKey].ToString();

                    if (deleteKeyAfterCapture.Value.ToUpper() != "YES")
                    {
                        HttpContext.Current.Session.Remove(SessionKey);
                    }

                    if (isHidden.Value.ToUpper() != "YES")
                    {
                        if (!string.IsNullOrWhiteSpace(CssClass))
                        {
                            CssClass += " hidden";
                        }
                        else
                        {
                            CssClass = "hidden";
                        }

                    }
                }
            }
        }
    }
}

As the properties are already present we can just reuse them. The problem is that the properties for the complex structures like the BooleanField cannot be handled directly and they need to be taken from the ParametersDictionary. In WFFM 2.5 there is an extension method for getting values from the ParametersDictionary(and any other dictionary basically :)). So it is possible to replace the KeyValue Pair selections with the following if the target version is 2.5:


string deleteKeyAfterCapture = Sitecore.Forms.Mvc.Extensions.DictionaryExtensions.GetValue(this.ParametersDictionary, "deletekeyaftercapture");
string isHidden = Sitecore.Forms.Mvc.Extensions.DictionaryExtensions.GetValue(this.ParametersDictionary, "ishidden");

The only thing remaining is registering the field with WFFM. This is achieved by creating an item of from the Field Type Template under /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types. (My personal preference is to place them under /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/Custom, but any other folder will do it).

The main values that need to be populated are:

  1. Assembly – The assembly in which the Main (WebForms) class is located.
  2. Class – Fully Qualified Class Name of the Main (WebForms) class.
  3. MVC Type – Required only if the field is going to be used in MVCForm Rendering. Must be in the following format – [FullyQualifiedClassName], [AssemblyName]

Here is an example with the values set:

WFFM Field

And it is done ! The field type is now selectable in the form designer and the properties are edited from the left hand menu, as it can be seen on the screenshot bellow!

Form Designer

The full code for the field can be found on BitBucket .

 

2 thoughts on “WFFM Session Aware Single-Line Text Field”

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s