Custom Macro Parameter Types Editor Odyssey

Written by @marcemarc on Tuesday, 16 February 2016

Hey this may not be obvious but creating Custom Macro Parameter Type's in Umbraco 7 has gotten insanely easy, without anyone really shouting about it. (or if they did I wasn't listening properly, I do apologise - I bet there's something on Tim Geyssens' excellent nibble.be blog about it - but in fact if you wondered about this and looked in the official docs:

https://our.umbraco.org/documentation/Extending/Macro-Parameter-Editors/

it says:

"If you want to create a new macro parameter editor you will need some c# programming and database knowledge:

First create a class deriving from a webcontrol and implement the IMacroGuiRendering interface. Afterwards, open your database editor. Find the cmsMacroPropertyType table and add the a new property editor."

Boo, that sucks! and it's also not true anymore!

Because now in the wonderful world of Umbraco 7 and angularJS - if you can create an Umbraco Property Editor, you can create a custom Macro Parameter Type Editor too!

The secret (shsssshhh) is to create an angularJS property editor, as you normally would, then in the package.manifest file; add the property:

isParameterEditor and set it to true.

that's it.

Not only will your editor appear in the list of property editors, it will now be available as a Macro Parameter Type too !!

undefined

Example, (always you want an example).

Well in the real world, I often have to build Umbraco sites where editors insert images into a Rich Text Area. (as not everyone is weaned onto using the grid yet). Now you might want that inserted image to have very specific markup ie class="responsive-image", and have a caption underneath, or use the new html5 picture element that all the cool kids are talking about instead of the img tag.

So this could lead you to abandoning the Insert Media button and creating a macro instead to insert the image into the rich text editor, you can specify a parameter of media picker type; and then be very specific about the markup that gets written out for the picked image.

undefinedWhich is all great and that but,... then the editor wants to align the image right or left amongst their text. Well you can create another parameter which is a textbox and have them type L or R into it or maybe create another Macro called 'Insert Image Right' to add the floating markup but it doesn't feel awesome. What you really want to provide is a nice radio button list to infer the options for positioning the image.

The default Macro Parameter Types are a bit lacking when it comes to this kind of thing.

So let's create a custom 'ImagePosition' Macro Parameter Type editor, to provide radio button options of how to position the inserted image, that we can then read in our macro implementation to apply relevent markup / css classes etc.

This is what our package.manifest file looks like:

{
 "$schema": "/App_Plugins/manifestSchema.json",
 "propertyEditors": [ 
 {
 "alias": "tooorangey.ImagePosition",
"name": "Image Position",
 "isParameterEditor": true,
 "editor": {
 "view": "~/App_Plugins/tooorangey.ImagePosition/ImagePosition.html",
 "valueType": "STRING"
}}],
 "javascript": [
"~/App_Plugins/tooorangey.ImagePosition/ImagePosition.controller.js"
 ]
}

Our View:

<div ng-controller="tooorangey.ImagePositionController">

<div class="radio" ng-repeat="position in positions" id="selectstatus-{{position.Name}}">
 <label>
 <input type="radio" name="position" ng-change="handleRadioClick()"
 ng-model="model.value" value="{{position.Name}}">{{position.Name}}
</label>
 </div>
 </div>

Our Controller:

(I'm hardcoding the options here, there isn't the concept of prevalues for Macro Type Parameter Property Editors, but you could read the values in from an API endpoint etc

angular.module("umbraco").controller("tooorangey.ImagePositionController", function ($scope) {

 if ($scope.model.value == null) {
    $scope.model.value = 'FullWidth';
}

$scope.positions = [
    {
    Name: 'FullWidth'
   },
    {
    Name: 'Left'
    },
    {
  Name: 'Right'
   },
   {
   Name: 'Center'
   } 
];

 $scope.handleRadioClick = function (status) {
 // alert($scope.model.value); 
 };
});,

we can then read the parameter in our macro using:

var imagePosition = Model.GetParameterValue<string>("parameterAlias");

and depending on this value align our images appropriately.

In conclusion it does kind of mean you can kind of go to town on creating custom Macro Parameter Types to make the editing experience more delightful or at least be aware it's easy to re-use existing property editors on macros parameter types.