Creating your first rail

What you will learn

In this lesson, you will discover a Dana vendor ready to use for common components of TV application. You will create a rail populated with data coming from your VodService.

Final visual result of this lesson will remain unchanged, but the buttons will be created dynamically based on data.

Add Dana components

To speed up development, Dana offers components for common TV design needs. You will find rail, grid, marquee… Here you will use RecyclingListView to create a menu on top of your CatalogScreen.

First of all, you need to install dependency to @dana/vendor-components:

npm i --save-dev @dana/vendor-components

And add it to your profiles:

{
    "base-css": {
        "base": {
            "name": "Css",
            "vendors": [
                "@dana/renderer-css",
                "@dana/vendor-components",
                "customBE"
            ]
        }
    },
    "base-lightning": {
        "base": {
            "name": "Lightning HTML5",
            "vendors": [
                "@dana/renderer-lightning-html5",
                "@dana/vendor-components",
                "customBE"
            ]
        }
    }
}

Note

Do not forget to relaunch your npm start to apply changes made in the profile.

Create a rail and set your button in it

In scripts/app/ui/views, create a new file named MenuListView.js. This class will inherit from RecyclingListView. You need to define 2 properties:

  • itemViewClass: the class to be used for each item of your list,
  • itemMargin: the margin between each item of your list

RecyclingListView will create as many child views as necessary to display all data. Scalability of this component is an advantage when creating list with a big number of elements. While navigating, children will be reused and new data will be set to change display.

In AppTheme, add a SCREEN_HORIZONTAL_MARGIN:

statics: {
    SCREEN_HORIZONTAL_MARGIN: 50
}

New file content should be as follows :

import $RecyclingListView from "@RecyclingListView";
import $ButtonView from "@ButtonView";
import $Theme from "@Theme";
import $MHListNavigation from "@MHListNavigation";
import $MBindingRecycling from "@MBindingRecycling";

/**
 * Display menu items
 *
 * @name MenuListView
 * @class
 * @extends RecyclingListView
 * @property {FixedRightNavigationType} navigationType Navigation type
 * @property {ButtonView} itemViewClass Class used for item of the list
 * @property {number} itemMargin Margin between items
 */
export default $RecyclingListView.declare("MenuListView", {
    properties: /** @lends MenuListView.prototype */ {
        itemViewClass: () => $ButtonView,
        itemMargin: 20
    },

    style: {
        height: $ButtonView.TEXT_HEIGHT + 2 * $ButtonView.VERTICAL_MARGIN,
        width: $Theme.FULL_SCREEN_WIDTH - $Theme.SCREEN_HORIZONTAL_MARGIN * 2
    }
});

Traits / Mixins overview

In object-oriented programming (OOP) languages, a mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes. This allow to mutualize code and inject it into other classes. You can not use a mixin “as it”, it should be added in another class in any case. Dana supports this concept and multiple classes are using it to add behaviour.

Caution

Even if mixin provides another way to mutualize code, simple inheritance should be preferred for every case of inheritance. Mixins are used for behaviour that needs to be be mutualized, like MFocusable. Even if it is not forbidden, inheritance of mixins is discouraged because it leads to bad maintainability.

For the list, you will use 3 mixins:

  • MHListNavigation: used for horizontal navigation
  • MBindingRecycling: used to bind position of item to precedent item in the list
  • FixedRightNavigationType: used to define navigation behaviour of the list (need to be defined as a navigationType property)

Note

Mixins are prefixed with M to be easily recognizable.

import $FixedRightNavigationType from "@FixedRightNavigationType";

export default $RecyclingListView.declare("MenuListView", {
    traits: [$MHListNavigation, $MBindingRecycling],
    properties: /** @lends MenuListView.prototype */ {
        navigationType: () => $FixedRightNavigationType
    },
});

Caution

Keyword traits allow you to declare mixins to be applied to the class.

Update ButtonView

To be usable in RecyclingListView, ButtonView should inherit from RecyclingItemView or use mixin MRecyclingItem. It should also implement setData method. It is responsible to use item data, displaying the associated information. Here you will set the catalog name in your TextPrimitive.

import $MRecyclingItem from "@MRecyclingItem";

export default $View.declare("ButtonView", {
    traits: [$MRecyclingItem],
    methods: /** @lends ButtonView.prototype */ {
        setData: function (data) {
            this.text.text = data.name;
        }
    },
});

Prepare CatalogScreen

As we are going to use the new child in the screen, start by cleaning it. Remove all mention of ButtonView:

  • remove import
  • remove button1 and button2 from children,
  • remove button1 and button2 from style,
  • remove left and right methods,
  • remove content of method connectData

Now:

  • import MenuListView,
  • add MenuListView in children,
  • add style to place the menu properly on screen, in style,
  • retrieve data for menu by calling getCatalogs in prepareData,
  • set data to the menu by calling setData in connectData
import $MenuListView from "@MenuListView";
import $Theme from "@Theme";

xport default $AppScreen.declare("CatalogScreen", {

    properties: {
        vodService: {class: $VodService}
    },
    children: /** @lends CatalogScreen.prototype */ {
        menu: {class: $MenuListView}
    },

    style: {
        menu: {
            x: $Theme.SCREEN_HORIZONTAL_MARGIN,
            y: 20
        }
    },

    methods: /** @lends CatalogScreen.prototype */ {
        prepareData: function (context) {
            return this.vodService.getCatalogs().then(data => {
                return {
                    menu: data
                };
            });
        },
        connectData: function (context) {
            this.menu.setData(this.data.menu);
        }
    }
});

Note

Result of prepareData could be an object you created. It is useful when you need to retrieve multiple information.

You can launch your application and see that 2 buttons are displayed, and you can navigate between them using right and left key of your keyboard.

Summary

To summarize, during this lesson you have :

  • used the component RecyclingListView,
  • discovered mixins