Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Matt Brailsford
Matt Brailsford

Posted on • Edited on • Originally published atmattbrailsford.dev

     

Reusing Umbraco Properties in Umbraco v14

When building user interfaces in Umbraco v14, occasionally there comes a time when you need to build a form based on some dynamically defined properties. One such example in Umbraco Commerce is how Payment Providers expose the settings they need for configuration.

Payment Provider Settings

When it comes to capturing this configuration, we ideally don't want to have to define these forms manually. Instead, it would be much better if we could use the exposed setting definitions as a pseudo doctype and dynamically render the form reusing the built in property editors in Umbraco to allow capturing different value types.

Data

I won't in this post go into the server side configuration for the payment provider settings, but needless to say, we have a REST endpoint that returns a JSON configuration for our settings similar to the following:

[{"alias":"continueUrl","label":"Continue Url","description":"The URL to continue to after the provide has done processing","editorUiAlias":"Umb.PropertyEditorUi.TextBox"},...{"alias":"textMode","label":"Test Mode","description":"Whether to run in test mode or production mode","editorUiAlias":"Umb.PropertyEditorUi.Toggle"}]
Enter fullscreen modeExit fullscreen mode

In addition, our Payment Method entities which hold the configuration values have a properties collection on it similar to the following:

{"id":"e06f29df-74fa-4ec8-8240-acccda44e702","alias":"invoicing","name":"Invoicing","properties":{"continueUrl":"/checkout/continue","cancelUrl":"/checkout/cancel","maxRetries":12,"testMode":true}}
Enter fullscreen modeExit fullscreen mode

Component

Lets start with a basic component that will be responsible for rendering out form.

@customElement("my-component")exportclassMyComponentElementextendsUmbElementMixin(LitElement){render(){returnhtml`TODO`}}exportdefaultMyComponentElement;declareglobal{interfaceHTMLElementTagNameMap{"my-component":MyComponentElement;}}
Enter fullscreen modeExit fullscreen mode

Lets now setup a couple of stateful variables to hold our data structures in and define a constructor that is responsible for populating those properties.

@customElement("my-component")exportclassMyComponentElementextendsUmbElementMixin(LitElement){@state()_settings:Array<MySettingType>=[];@state()_model?:MyEntityType;constructor(host:UmbControllerHost){super(host);// Some code to fetch and populate the _settings + _model}render(){returnhtml`TODO`}}...
Enter fullscreen modeExit fullscreen mode

I'll leave the fetching of the data up to you as it's not the important part, but we can move on with the knowledge we should now have some data in variables in the structures outlines above.

Rendering

The two components that are key to reusing umbraco properties are theumb-property-dataset and theumb-property.

Lets initially setup our rendering function as follows:

render(){returnhtml`<umb-property-dataset>${repeat(this._settings,(itm)=>itm.key,(itm)=>html`<umb-property                alias=${itm.alias}                label=${itm.label}                description=${itm.description}                property-editor-ui-alias=${itm.editorUiAlias}>            </umb-property>`)}    </umb-property-dataset>`}
Enter fullscreen modeExit fullscreen mode

I'll get to why we need aumb-property-dataset in a second, but for now we'll just need to know that we must have one wrapped around our rendered properties.

Inside theumb-property-dataset tag, we'll then loop through our setting definitions and use theumb-property component, passing through thealias,label,description andeditorUiAlias from our settings.

If we were to now look on our front end you should now see your properties rendering, complete with labels, descriptions and the reusing of umbraco property editors.

Pretty neat for relatively little code 😎

Binding

Right now however, there won't be any values in our properties, and we aren't capturing any value changes either.

This is where theumb-property-dataset comes into play. Rather than needing to set values and handle input events for all properties, we instead populate a single values collection, and listen for a single event from theumb-property-dataset instead.

The first thing we need to do is massage our property data into the expected format. Theumb-property-dataset takes in a value of typeArray<UmbPropertyValueData> whereUmbPropertyValueData is defined as:

exporttypeUmbPropertyValueData<ValueType=unknown>={alias:string;value?:ValueType;};
Enter fullscreen modeExit fullscreen mode

In our component, lets introduce another stateful variable and populate it after we populated our other settings.

@customElement("my-component")exportclassMyComponentElementextendsUmbElementMixin(LitElement){...@state()_values:Array<UmbPropertyValueData>=[];constructor(host:UmbControllerHost){super(host);// Some code to fetch and populate the _settings + _modelthis._values=this._settings.map(setting=>({alias:setting.alias,value:this._model?.properties[setting.alias]}));}...}...
Enter fullscreen modeExit fullscreen mode

Here we loop through all our setting definitions, creating a newUmbPropertyValueData entry populating it's alias with the setting alias and then it's value with the value of that setting found in our entity model.

With our property values now in the format we need, we can update our render function as follows:

render(){returnhtml`<umb-property-dataset        .value=${this._values}>${repeat(this._settings,(itm)=>itm.key,(itm)=>html`<umb-property                alias=${itm.alias}                label=${itm.label}                description=${itm.description}                property-editor-ui-alias=${itm.editorUiAlias}>            </umb-property>`)}    </umb-property-dataset>`}
Enter fullscreen modeExit fullscreen mode

Here we have bound our_values variable to thevalue attribute of theumb-property-dataset component and that is all we need to do to get our store values to display.

Change Handling

The last part of the puzzle is reacting to change and persisting the updated values back.

For this we'll create a single event handler to capture all changes like so.

@customElement("my-component")exportclassMyComponentElementextendsUmbElementMixin(LitElement){...#onPropertyDataChange(e:Event){// Grab the valueconstvalue=(e.targetasUmbPropertyDatasetElement).value;// Convert the value back into an objectvardata=value.reduce((acc,curr)=>({...acc,[curr.alias]:curr.value}),{});// Update our modelthis._model.properties=data;}...}...
Enter fullscreen modeExit fullscreen mode

Here we get the data set value (which contains values for all our settings) and then we convert it into the same structure of our models property collection, and then reset the value back on the model.

Again, I'll leave the persistence side of things to you here, but for this example I'm just writing back to the main entity model..

Finally, we'll update our render function again to attach our event handler.

render(){returnhtml`<umb-property-dataset        .value=${this._values}        @change=${this.#onPropertyDataChange}>${repeat(this._settings,(itm)=>itm.key,(itm)=>html`<umb-property                alias=${itm.alias}                label=${itm.label}                description=${itm.description}                property-editor-ui-alias=${itm.editorUiAlias}>            </umb-property>`)}    </umb-property-dataset>`}
Enter fullscreen modeExit fullscreen mode

And that's it. We now have a dynamically generated form that reuses umbraco property editors for input collection and where we can capture and store the user input.

I hope you found this post helpful.

If you'd like to see an example implementation of using theumb-property-dataset andumb-property elements there is an example in the Umbraco BackOffice code basehere.

Until next time 👋

Top comments(1)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
konius profile image
Paulius Putna
  • Joined

Hi Matt,

Is this supposed to be some code for inspiration or a working example (with some parts missing)?

I'm struggling get the data saved on a document type using this method.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

9x Umbraco MVP | Half of Outfield Digital | Co-founder of Codecabin | Owner and creator of Vendr and Konstrukt Umbraco packages
  • Location
    UK
  • Work
    Umbraco Developer at Outfield Digital Ltd
  • Joined

More fromMatt Brailsford

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp