One our fellow in world.episerver ask question about the custom property in EpiServer. This has been discussed many many time in forum and blogs but I couldn’t be able to find simple version to reference. In this post I’m trying to describe this in simple way!

Requirement: We want to get ahtur “First Name” and “Last Name” and store that into object with type named “Author” as below:

    public class Author
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

 

So eventually in AlloySample having something like:

public class ArticlePage : StandardPage
{
	[UIHint(AuthorEditorDescriptor.UIHint)]
	[BackingType(typeof(PropertyAuthor))]
	public virtual Author Author { get; set; }
}

 

Solution:

  1. First create Alloy sample
  2. Definitely we need type so create “Author” under “Model” folder:
    public class Author
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
  3. PropertyDefinitionTypePlugIn: PropertyDefinitionTypePlugIni is used to introduce a “Type” as Episerver predefined “Type”!  The type needs to be based on  “PropertyString (long or short) or ProperttNumber.  So this will tells Episerver which  property “VALUE” (in our example complex type named  ‘Author’) need to be stored as ‘string’ or ‘int’. So what we do is serialize object as JSON string and store it as ‘string’ in DB. I will speak on separate post about performance considerations when you are building these kind of ‘Custom Properties’. So below is descriptor:
        [PropertyDefinitionTypePlugIn]
        public class PropertyAuthor : PropertyLongString
        {
            public override Type PropertyValueType
            {
                get { return typeof(Author); }
            }
    
            public override object Value
            {
                get
                {
                    var value = base.Value as string;
    
                    if (value == null)
                    {
                        return null;
                    }
    
                    return JsonConvert.DeserializeObject<Author>(value);
                }
    
                set
                {
                    if (value is Author)
                    {
                        base.Value = JsonConvert.SerializeObject(value);
                    }
                    else
                    {
                        base.Value = value;
                    }
                }
            }
    
            public override object SaveData(PropertyDataCollection properties)
            {
                return LongString;
            }
        }

     

  4. EditorDescriptor: With EditorDescriptor we instruct episerver UI  how to render the control in admin area. So we in our case we need two text boxes for “First Name” and “Last Name”  and admin can change the value. To achieve this we need to instruct Episerver to use what JS to render our property on admin area:
        [EditorDescriptorRegistration(TargetType = typeof(Author),
            UIHint = AuthorEditorDescriptor.UIHint)]
        public class AuthorEditorDescriptor : EditorDescriptor
        {
            public const string UIHint = "Author";
            private const string AuthorProperty = "alloy/editors/AuthorProperty";
    
            public AuthorEditorDescriptor()
            {
                ClientEditingClass = AuthorProperty;
            }
        }

     

  5. Dojo JS! This bit is most mysterious bit.  Episerver is using Dojo framework on admin area. So rendering will be happen  on client side! To achieve this  we need to create two file. One is HTML which is “template” file use by JS as template for rendering and actual JS file which will be called first to fire the  rendering process! So let’s create JS first.  Create asda in:captureAuthorProperty.js:
    define([
        "dojo/_base/declare",
        "dijit/_Widget",
        "dijit/_TemplatedMixin",
    
        "dojo/text!./templates/AuthorProperty.html",
        "dojo/dom",
        "dojo/domReady!"
    ],
    function (
        declare,
        _Widget,
        _TemplatedMixin,
        template,
        dom
    ) {
        return declare("alloy/editors/AuthorProperty", [
            _Widget,
            _TemplatedMixin], {
                templateString: template,
                _onFirstNameChange: function (event) {
                    if (!this.value)
                    {
                        this.value = { firstName: '', lastName: '' };
                    }
                    this.value.firstName = event.target.value
                    this._set('value', this.value);
                    this.onChange(this.value);
                },
                _onLastNameChange: function (event) {
                    if (!this.value) {
                        this.value = { firstName: '', lastName: '' };
                    }
                    this.value.lastName = event.target.value
                    this._set('value', this.value);
                    this.onChange(this.value);
                },
                _setValueAttr: function (val) {
                    if (val) {
                        this.firstName.value = val.firstName;
                        this.lastName.value = val.lastName;
                        this._set('value', val);
                    }
                },
                isValid: function () {
                    return true;
                }
            }
        );
    });

     

    AuthorProperty.html:

    <div>
        <label for="firstname">First name</label>
        <input type="text" data-dojo-attach-point="firstName" 
               name="firstname"
               data-dojo-attach-event="onchange:_onFirstNameChange" />
    
        <label for="lastName">Last name</label>
        <input type="text" data-dojo-attach-point="lastName" 
               name="lastName" 
               data-dojo-attach-event="onchange:_onLastNameChange" />
    </div>

    Hope it help.