This is one of a series of posts looking at migrating Umbraco packages to Umbraco 14 and the new backoffice. Other posts in this series:
- Introduction
- Upgrading to Umbraco 14 Preview
- Creating a Property Editor With Umbraco 14
- Adding and Deleting Criteria
As of last time I posted in this series, I had a partially working property editor for Personalisation Groups. It could display the information stored against the property, and I'd solved a couple of challenges around retrieving external data and injecting scripts dynaically at runtime.
There's not been too much progress since, but I've picked up a few more things along the way that I'll include as a bit of a "grab-bag" in this post.
First step to make the data editable was wiring up some button clicks. In angularjs we are used to:
<button type="button" ng-click="delete($index)">Delete</button>
With Lit, the syntax is:
<button type="button" @click=${() => this._removeCriteria(index)}>Delete</button>
With Lit being more of a library than a framework like angularjs, we likely end up using more native JavaScript like getElementById. The encapsulated nature of the web components approach means we don't have to worry about our IDs clashing with something from core or another package loaded in the Umbraco backoffice. But we do need to remember to reference the element not via document.getElementById
, but rather with this.shadowRoot?.getElementById
. For example, to add a new criteria to a group, I find the value of the selected one to add via:
const selectedCriteriaAlias = (this.shadowRoot?.getElementById("availableCriteriaSelect")).value;
In order to progress further I did a bit of digging around in the CMS code, and found a property editor that's fairly similar to what I'm building - the multi-URL picker. This also displays a list of items, with each on editied in a modal. The core property editors are generally broken into two files. For example the mult URL picker has a property editor element that in turn imports and uses an input element.
I decided to break my editor up in a similar way, which was mostly straightforward but I did have a few issues that took me some time and help to resolve.
One was the incoming state to the input element being immutable, so if I wanted to add a new criteria to the array, I'd get an error like Cannot add property 1, object is not extensible
. This was resolved by taking a copy of the property data when it's first loaded into the input element.
Another was that when updates were made, they weren't being reflected in the UI. At this points I found I had to make explict calls to Lit's this.requestUpdate()
method.
The final one was simply getting anything other than my entry-point JavaScript file being included in the built output. That was fixed with exports, making sure the input element is also exported from the property editor element.
My last, as yet incomplete, effort for now was attempting to adapt the code in the multi-URL picker to open a modal for editing the definition of the group. There I ran into an issue that a key base class used by the core CMS modals - UmbModalBaseElement
- is marked as internal. Fortunately though I can see that's the case of of the latest preview release (preview 3, at the time of writing), but it has changed when I look at the latest code in the GitHub repo. So this will be one to wait for preview 4 for, and give it another go.
Excellent, Andy!
ReplyDeleteSmall tip for queriying into the shadowroot with Lit; you can use the @query decorator, which can also cache the result for you: https://lit.dev/docs/api/decorators/#query
You'll use it by setting a property on the class:
@query('#availableCriteriaSelect', true)
private _button?: HTMLButtonElement;
and then access it wherever:
const selectedCriteriaAlias = this._button?.value ?? '';
Also; you can use the UI library to make the buttons look nice - should be enough to replace "button" with "uui-button" 😎
Nice - thanks for the tips Jacob. I'll look at these updates for the next round.
Delete