Customizing your component

What you will learn

In this lesson, you will learn how to use binding functions but also when you should use them and when you should prefer fixed value. You will also learn where you should mutualize style properties value to keep a good maintainability of your project.

Dynamic style values

You now have a LoaderView with multiple primitives. But many values are fixed… If you change text value, its width should change, and you will need to update background width too. With fixed size value, you can’t. But binding functions are here to make it possible.

Binding functions

Style properties can take a function as a value, called “binding function”. Those functions will allow you to compute value of the property based on other properties value. Moreover, if the value of the other property change, value of your property will be automatically updated.

For example, given the following declaration :

myProp: ({myOtherProp}) => myOtherProp

Your property myProp will always equal to your property myOtherProps. When myOtherProp changes, myProp will automatically be updated when we will try to get its value.

Danger

Even if binding functions are very useful, it is coming with a cost for performances. Each time you create a binding function, the framework is creating a watcher for properties of your function at creation time of your component. Even if you only execute your binding function once, it has a cost at creation. So to keep a performant application, be careful to the amount of binding functions.

Dynamic size applied on the Loader

What you are going to achieve is the following:

  • make text width automatic
  • make background width depends on text and image width with a margin
  • make LoaderView width depends on background width
  • make text to be vertically align depending on LoaderView height

Automatic text width

First of all, remove width on text and use isAuto_width property by setting this :

style: {
    text: {
        isAuto_width: true
    }
}

Note

Linter is raising an issue @dana/no-use-width-height-auto. Depending on the renderers, auto sizing could have a performance cost. It is recommended to use this property only when required. Here it is exactly what you are trying to achieve, so disable the rule for this line.

style: {
    text: {
        // eslint-disable-next-line @dana/no-use-width-height-auto
        isAuto_width: true
    }
}

Background width depends on text and image width

Bind the background width to text width by declaring a function as value of your background’s width.

style: {
    background: {
        width: ({parent}) => parent.text.width + parent.image.width + 30
    }
}

When using a binding function, context set to the function is the element himself. So here this is the background RectanglePrimitive. By using the brackets, we are using destructuring and are able to access to properties of RectanglePrimitive. All primitives and views have access to their parent thanks to the property parent. And here it allows you to access to the LoaderView and so by accessing to text property of it, you can access the TextPrimitive.

LoaderView width depends on background width

And do the same for the LoaderView:

style: {
    width: ({background}) => background.width
}

Vertical align of text

You have done simple binding by just using property from other elements. But binding function can be used to make calculation between self and parent properties. To set y value of the text, you can be based on text height inside its parent height :

style: {
    text: {
        y: ({parent, height}) => (parent.height - height) / 2
    }
}

Test by updating text

Now try to update the text content, you should see the background and the LoaderView updates themselves accordingly.

More warnings (if needed)

As you can see, the way you now have written your LoaderView seems a lot easier to maintain now. If you change one property, other primitives will react to resize themselves. But this is often not the best choice because :

  • with TV applications you will probably need to address low performance devices,
  • there are other ways to mutualize things like you are going to see in the second point of the lesson

In some case, you don’t have better options than binding functions, for example with text width depending on your language. But keep in mind that you should always keep an eye on the number of binding in your screens because it could have terrible impacts. To help you in this job, you can see the number of binding in the console of your debugger each time a screen is displayed.

[anonymous][showDisplayScreenInfo]
   * Screen   : splashScreen
   * Children : 1 Views / 1 Primitives
   * Binding  : 8

Using a theme

Theme class will be useful in your developments. As previously mentionned, mutualizing style properties values will help you to keep a good project maintainability and avoid overuse of binding. When creating an application, you will probably have a design system to follow with a number of colors, size, font families… Some of those values are going to be common to all your components. In that case, it is recommended to store them in Theme. Some properties will also be only specific to a component. In that case, store this value in your component class. In all cases, store them in statics properties because those properties are not watchable and so you won’t increase binding number even if writing a function inside value of your property.

Caution

statics keyword is used to define static properties. To access to those properties, you should access them from class itself and not from instance.

Open AppTheme file and move all application style properties in it :

export default $AbstractTheme.declare("AppTheme", {
    statics: /** @lends AppTheme */ {
        H1_FONT_SIZE: 40,
        COLOR_GREY: "AAAAAA",
        LOGO_DANA_WIDTH: 323,
        LOGO_DANA_HEIGHT: 140
    }
});

In LoaderView, create a margin static value :

statics: /** @lends LoaderView */ {
    MARGIN: 20
}

And use them in your LoaderView by replacing existing values :

style: {
    width: ({background}) => background.width,
    height: $Theme.LOGO_DANA_HEIGHT,
    background: {
        width: ({parent}) => parent.text.width + $Theme.LOGO_DANA_WIDTH + 2 * parent.statics.MARGIN,
        height: $Theme.LOGO_DANA_HEIGHT,
        fillColor: $Theme.COLOR_GREY
    },
    text: {
        x: ({parent}) => $Theme.LOGO_DANA_WIDTH + parent.statics.MARGIN,
        size: $Theme.H1_FONT_SIZE
    },
    icon: {
        width: $Theme.LOGO_DANA_WIDTH,
        height: $Theme.LOGO_DANA_HEIGHT,
        x: ({parent}) => parent.statics.MARGIN
    }
}

Summary

To summarize, during this lesson you have :

  • use binding functions
  • mutualize style property values

To go further on those concepts, you can parcourate the following documentation pages :