Components - Eliminate "Property Fatigue": Use a Properties Record!
Photo by Tim Gouw: https://www.pexels.com/photo/man-in-white-shirt-using-macbook-pro-52608/
In my first ever article, I mentioned one of my component tricks of using a Properties record instead of individual properties to avoid "property fatigue": Today I'm going to discuss what exactly this is and how to implement it into your own components. 🦀
It's an idea originally shown to me by James Ryan which I wanted to share.
🥱 Property Fatigue?
Yeah, "Property Fatigue".
It's when you have a component built and you're doing the right thing by making it nice and customizable.
👆 Here is but a humble component, containing one control (A slider). The point of this component is ultimately, to give other makers a way of easily implementing a stepped slider. For example, I have a minimum value of 100 and a maximum of 1000, I want to step up in 100 increments.
Nothing groundbreaking here, but we don't really want to give out a component in PowerApps blue either, so we need a way for other makers to customise this.
Functionally, our component already works and that's thanks to some input data properties we've already implented: Min, Max and Step; these are all number data types.
So let's turn our attention to the slider itself.
We probably want the following configurable:
Colour of the Rail
Colour of the Handle
Size of the Handle
Thickness of the Rail
Left/Right Padding of the Rail
The border for the control
...
This goes on, we have hover fills, disable fills, the DisplayMode!
We could go and create each property individually:
Wire each property up to each control property, and we're done!
Go ahead and put that bad boy in your App 🦀
👆 Welcome to property fatigue.
Okay, I've been lazy here and didn't go through with all of it, but imagine if I had! That's a lot of properties even now for someone to manually fill in.
What's also poor game is that:
Properties can't be grouped or categorised, much like you see in standard components
Whilst you can tab through these, you need to launch the Formula Bar to add anything useful like variables anyway.
These settings aren't easily transportable between apps. Or, put it another way, the config for this component can't be easily shared with others.
🤔 There must be a better way.
Enter the Properties Record 🦀
It seems small, but an input record is helpful in this scenario.
The benefits include:
Editable properties from one location
Settings stored in text, copy and paste to share/reuse
Properties can be grouped logically, comments can even be added!
So, sounds like this solves all our original problems. Let's see what it looks like in practice:
We could use a record like this below as a starting point.
{
Colours:
{
PrimaryColour: ColorValue("#111111"),
SecondaryColour: ColorValue("#555555"),
BackgroundColour: Color.Orange
},
Font:
{
'Font-Family': Font.'Courier New',
Sizes:{
Heading: 21,
Action: 12,
Text: 13}
},
Slider:
{
Rail:{
'Rail-Size': 13,
'Rail-Thickness': 2},
Handle:{
'Handle-Size': 20,
'Show-Value': false},
Padding:{
Top: 0,
Bottom: 0,
Left: 10,
Right: 10}
}
}
This gives us some colours, typography and some specific Slider options as well.
We'll need to create a properties record and specify this base record in this input property, so our component knows what properties are available. Add/Remove from this at your own will.
But see how we're grouping properties in nested records? When we come to mapping these to the control in the component, we can use dot notation to go through the record and get the properties we need:
HandleSize = 'Stepped Slider'.Properties.Slider.Handle.'Handle-Size'
And what's more, you could actually reuse this method across other components as well. Keeping this approach consistent means makers using your components can reuse customised property records with other components. Makers can even store the record as a global variable and call it in each component, provided you're designing it in such a way that it's reusable.
This really aligns with reusability and generally makes things easier for other makers.
What about overriding particular controls? 🔧
This is achievable with the Coalesce() function.
Example: We want to be able to override Labels with a different font family over the default specified. The Properties record may look something like this:
{
Colours:
{
PrimaryColour: ColorValue("#111111"),
SecondaryColour: ColorValue("#555555"),
BackgroundColour: Color.Orange
},
Font:
{
'Font-Family': Font.'Courier New',
Sizes:{
Heading: 21,
Action: 12,
Text: 13}
},
Label:
{
Font:{
'Font-Family': Font.'Dancing Script'},
Padding:{
Top: 0,
Bottom: 0,
Left: 10,
Right: 10}
}
}
We can use the Coalesce() function in the component on the Label's Font Property to handle this:
Label.Font = Coalesce( //If Label specified font isn't present, fall back to standard
'Label Component'.Properties.Label.Font.'Font-Family',
'Label Component'.Properties.Font.'Font-Family')
TL;DR 📚
Use a record input property over individual properties.
Allows using Dot-notation to access properties within nested records
This helps with the theming and customisation of components, helping to make them more reusable. Keep the record consistent across all your components.
Give the option to override default properties with specific control-based nested records, and utilise Coalesce() to handle this.
Hopefully, you've found this article and tip helpful. Check out some of my previous articles on the new component property types: