Views: 8936
Number of votes: 10
Average rating:

Strategies for Custom Properties in 7.5+

 

Any developer that has done more than a couple of EPiServer sites will recognize the need customizing properties / property types in order to give a smooth editorial experience. Typically, as you want properties that mimics the business area you are trying to describe, you find the need to connect to 3rd party sources, validate input, build-up complex properties, work with lists and so on. Back in the ‘good old days’ – as in before 7, you’d often end up doing a custom property type to support your need. You’d basically get an empty controls collection and could start building up the edit/on-page-edit and view mode experience for any given property. It pretty much gave you full control – but also meant a lot of work and a lot of ground-up customization…Of course there were open source to help you with that, but still. One open source project I was part of was this: http://propertypack.codeplex.com/ – in this blog post I’ll show that each of the property types included there can easily be done without dojo – and in fact without even doing custom properties in 7. Just a matter of configuring the built-in ones for the purpose.

From version 7 and up, the approach to custom properties has changed somewhat – and you now have more options to do what you want. Some new spells have found their way to the show – like ‘dojo’ and ‘dijit’ – and from my many talks with developers I find that I’m not the only one who has been a bit scared by the big unknown :-) Sadly I haven’t found time to spend the 3+ years at Hogwarts school of witchcraft and wizardry needed to master these new spells to perfection just yet. But it turns out it’s alright. Luckily there are many different approaches you can take without dojo – and more will come.

Think of it this way: we provide you with a growing set of lego-bricks (dojo/ui) to build your house with – if you’re missing a specific piece of lego to make your dream-house, you can of course try to mold the plastic yourself and construct a new brick – but odds are that with a bit of creativity you can work around it with other combined lego-pieces…

 

#1 Don’t customize the property type – adjust the implementation with attributes

First off, a good thing to keep in mind is that we (EPiServer) really do try to make it easy for everybody implementing sites on our platform. In fact, it’s one of main ambitions is to make YOU happy. Now, with new functionality like this there might still be a few rough edges, but every release in our continuous cycle will make that better. The ambition in this case is that most of the properties where you before 7 would have to make a custom property type and implement a lot of stuff from scratch can now be achieved much simpler in the property declaration. For instance deciding how editors should be exposed to the property, how it should be input validated, and even how it should be displayed (UIHints). To achieve this we try to mostly use standardized .NET Attributes made for the same purposes – but in a few cases we’ve been extending them with our own.

image

These are some of the most basic attributes you can add to a property. A nice detail here is of course that using the [Display] attribute you can set the ‘GroupName’ aka the TabName in edit-mode.image Use the SystemTabNames built-in class for the names of the default tabs if you want to populate those, or add a new name if you want a new tab. Tip: If you want stuff to show up in the Header, above the usual editing, that’s actually just a Tab as well, just use this:  [Display(GroupName=SystemTabNames.PageHeader)].

The typical attributes are pretty well documented in the SDK:http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-CMS/7/Content/Pages-and-Blocks/Attributes/.

You might also want to read http://world.episerver.com/Documentation/Items/Developers-Guide/EPiServer-CMS/75/Content/Properties/Property-types/ to understand stuff like [BackingType].

A much overlooked, but really essential part of good user interaction is validation of user input. That’s also easy here – just use attributes like [Required], [RegularExpression], [Range] or [StringLength] to impose limitations on the values.

 

#2 Custom Dropdownlists and multi-selects

Recently, we’ve also added some more specific attributes for other cases that would in the past have required custom properties – and that was very, very common. A good example of this is the selection lists. Often, you’ll find yourself in a situation where you will want to limit the editors input options to a select few. Some times you can hardcode in advance – like an Enum perhaps (E.g. ‘Where to show graphic? Left, Center, Right) and in other cases it require a serverside lookup in another data source (e.g. ‘Sales guy for this region? Adam, Alan, Bob, Charlie, …, Xenia). Both cases can now easily be solved with something like this

[SelectOne(SelectionFactoryType = typeof(YoutubeSelectionFactory))]
public virtual string MyYoutubeClip { get; set; }

In this case, I have made a selection factory that fetches the EPiServer channels youtube feed and offers it as drop-down list options.

image

image

I could of course also have had it as a [SelectMany] and perhaps used it to configure an entire playlist.

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/12/SingleMultiple-selection-in-EPiServer-75/

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2014/5/Enum-properties-for-EPiServer-75/

 

#3 Lists and Pointing to other content

Another really nice use of attributes is that for any property type that somehow involves pointing to other content (that being pages, blocks, media, products, folders) you can easily limit which content is selectable in that property using the [AllowedTypes(…)] attribute. In that you can specify a single type or an array of types that can be selected – and it works whether the property is a ContentReference, a PageReference, ContentArea or even a LinkCollection. And – even better – you can of course specify basetypes and interfaces as well.

A good example of a use of this could be that in your Image Gallery (or Caroussel) you only want Images to be dragged in, no blocks, no pages and no pdfs…..Just use a Content Area or LinkCollection as a container and let the editors knock themselves out…

 

#4 Customizing Edit and View experience – UIHints and Editor Descriptors to the rescue

So, now we can limit, validate, name and place properties – but what if we want them to be displayed in a special way – in view mode, in edit mode, in on-page-edit mode? [UIHint] is your buddy! It’s a standardized .NET method of indicating which approach to use when displaying a given property.

In EPiServer we have used EditorDescriptors to specify how a certain property should be rendered. EditorDescriptors is connected either as a ‘default’ to a specific base type – or to a base type and a UIHint.

You can create your own EditorDescriptors when you want to do something more advanced than what we do out-of-the-box, but let’s start just by exploring which ones you get built-in:

  • Block
  • BlockFolder
  • Document
  • Image
  • Legacy
  • LongString
  • MediaFile
  • MediaFolder
  • PreviewableText
  • Textarea
  • Video

These are all found in EPiServer.Web.UIHint. So, let’s say that I have a string property that I really want to expose as a plain text area to the editor? Easy!

[UIHint(EPiServer.Web.UIHint.Textarea)]
public virtual string MyTextArea {get;set;}

Or – what if I want to pick a MediaFolder thereby indicating that all images within should be used in my gallery?

[UIHint(EPiServer.Web.UIHint.MediaFolder)]
public virtual ContentReference {get;set;}

But..It doesn’t stop there. You can of course type in any string you want as a UIHint – and then either match it up to your own EditorDescriptor – or (and hold on, cause now it gets really awesome) you can implement an MVC view under Views/Shared/DisplayTemplates with the name of UIHint – like ‘Youtube.cshtml’. To return to my Youtube example from before. Remember, my property was just a string that the editor through a [SelectOne] dropdown list could set to any video in the EPiServer Youtube channel. After setting it, it would just store the Youtube key in the string. Now, all I have to do is apply a UIHint and implement an MVC view for that hint so it gets displayed like a proper embedded Youtube video:

@model string
<iframe width="420" height="315" src="//www.youtube.com/embed/@Model?rel=0" frameborder="0" allowfullscreen></iframe>

So now, I get this:

image

 

You can of course also go down the path of ‘I want to do my own EditorDescriptor’. This is typically the first step on the way to doing Dojo. In the EditorDescriptor you can for instance customize the SelectionFactory used (in fact SelectOne and SelectMany are just shortcuts to this), you can set which Dojo class to render, and you can modify the parameters send to the dojo class. But in fact, you can also do a lot more without really touching the dojo in an editor descriptor. A good example is this question I got the other day: “We want to do a Date picker – but the only thing built-in is a DateTimePicker – how do we get ‘just’ a Date picker?”.
As it turns out (thanks oh Linus-Guru) it would seem that most of the default dijit widgets (out-of-the-box dojo visual components) for forms can be snap-in replacements for episerver properties – and they are already included! All you need to do is to set the proper ‘ClientEditingClass’. In this case it was a simple matter of looking up the Dijit Examples, finding the DateTextBox and doing this:

image

Once I saw this, I started experimenting with other built-in dijit property types, and pretty soon I came across this cool slider:

image

Now, if only I could find a good use for it.

More Reading:

http://epiwiki.se/developing/properties/minimal-episerver-dojo-view-for-property

http://marisks.net/2014/04/11/episerver-writing-dojo-widget/

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/4/Sending-settings-from-the-server-to-your-editor/

 

#5 Need grouped / complex properties? Use Blocks

Before version 7, another typical need I saw was ‘Complex’ properties – as in Properties that in fact was a grouping of several properties treated as one. That’s one of the things I think was solved really well in 7.

All you have to do is basically to put them together in a Block – and use the Block as a property type. Yes, you can do that! Like this:


public virtual ButtonBlock MyButton { get; set; }

If you want to, you can in your Block definition specify that AvailableInEditMode=false – so your editors won’t be confused when they see it pop up whenever they are creating a block – although in some cases you can definitely have dual-use block types. Once it’s a property, you can access it through Html.PropertyFor as any other property – or you can call it’s sub-elements directly like @Model.CurrentPage.MyButton.ButtonText. Btw, we call these ‘Local Blocks’ as opposed to the regular ‘Shared blocks’.

image

There has even been some great experiments done with making properties grouped together inside a block dependent on each other – like the classic “Country/Region” dependency here.

 

#6 If all else fails – you can always go Legacy Style

Now that you have read through all of these tricks – you might still be left with a yet unaddressed need for a custom property. Well, don’t fear – Legacy Style properties are still here!

You can create a custom property type much like you’ve always done with EPiServer CMS – and use it. In fact, if you use the Visual Studio extension there’s even a template for it. There you can do pretty much anything you want – and all you need to do to expose the ‘old-style’ view?

[BackingType(typeof(MyProperty))]
[UIHint(EPiServer.Web.UIHint.Legacy)]
public virtual string Property1 { get; set; }

This will essentially create a big bad button that lets the editor open the old-time view in an overlay.

What’s next?

A lot of other great stuff is coming. One of the things I recently noticed is Linus’ approach to autocompleted properties. I can’t wait for this to be in the core.

http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2013/12/Auto-suggest-editor-in-EPiServer-75/

    (By robert.linde , 29 June 2014 12:30, Permanent link)

    Excellent post, I especially like the AllowedTypes-attribute. This is something that has been missing for a long time for LinkItemCollections and PageReference properties.

    I've written a blog post with some more in depth info on how to create custom dojo properties: http://robertlinde.se/post/custom-episerver-properties-with-dojo

    (By Martin Pickering , 01 July 2014 11:21, Permanent link)

    Thanks for this post.
    I have to confess that I am still freaked out by the dojo/dijit stuff.
    It seems like a lot of work (and even more praying/dark magic) to achieve a small thing. I think that I'll be doing everything I can to avoid needing to create dijits.
    But, on reflection, maybe that's a good thing?

    (By Johan Petersson , 01 July 2014 19:42, Permanent link)

    AllowedTypes attributes does not work on base classes or interfaces. But it would be awsome if it did! Should I file a bug report?

    (By Linus Ekström , 23 July 2014 11:07, Permanent link)

    @Johan: AllowedTypes should now work on base classes though you still have to apply a work around for interfaces.

    @Allan: There is now built in support for auto suggestion in the core: http://world.episerver.com/Blogs/Linus-Ekstrom/Dates/2014/7/Built-in-auto-suggestion-editor/

    (By David Strøm , 15 October 2014 09:04, Permanent link)

    And what about a strategy for a list og grouped / complex proerties?

    Let's say you need to have a variable list of your MyButton block on a page. Then you would need a "Create new button" editing option somewhat like you have with a LinkItemCollection.

    How would you go about doing that? Any hints / ideas?

    (By Guest , 06 May 2015 12:06, Permanent link)

    David did you make any inroads into your questions ? Im looking for something similar although might have to revert back to using the ElencySolutions.MultiProperty

  Please login to post a comment