How to use a native rail ?

Letโ€™s try to create the content rail like a simple title and a list of tile composed by an image and a movie name.

Native rail

Getting Started

Limitation

See current here

Architecture

The screen will declare a children <RailWithTitleView> which will be the aggregation of TextPrimitive and of the NativeRailElement.

CatalogScreenRailWithTitleViewNativeRailElementTextPrimitive

Step-by-step guide

Component declaration

First you can declare your view containing a rail with title.

Caution

landscapeTile and portraitTile are demonstration purpose tile that are embedded in the SDK.

export default $View.declare("RailWithTitleView", {
  children: /** @lends RailWithTitleView.prototype */ {
    title: {
      class: $TextPrimitive,
      text: ""
    },
    list: {
      class: $NativeRailElement,
      itemChooser: {
        key: "ratio",
        items: [
          {
            keyValue: "16-9",
            item: "landscapeTile"
          },
          {
            keyValue: "2-3",
            item: "portraitTile"
          }
        ],
        defaultItem: "landscapeTile"
      }
    }
  }
});

ItemChooser

Letโ€™s take quick look at the important property itemChooser.

  • key is the name of the property in the provided data model that will be used to choose in between item type
  • items declares the different type of item. Each item is composed of
    • a keyValue: if data.key === keyValue, then this type of item
    • an item: a type of tile that you will have to define
  • defaultItem: will be used if no item is matched

If you provide the following json to the rail along with the previous itemChooser:

{
  "name": "My movie",
  "ratio": "2-3"
}

It would draw a portrait tile due to key โ€œratioโ€ === โ€œ2-3โ€

Setting some data

Letโ€™s imagine that we have a service returning data with the following structure:

const data = {
  railName: "On Now",
  listData: [
    {
      name: "Che tempo fa",
      getImageUrl: function () {
        //method to retrieve image
      },
      ratio: "16-9"
    }
  ]
}

In the CatalogScreen declare a children RailWithTitleView, and get some data

export default $AppScreen.declare("CatalogScreen", {
  children: /** @lends CatalogScreen.prototype */ {
    railWithTitleView: {
      class: $RailWithTitleView,
    }
  },
  methods: {
    prepareData: function () {
      return myService.getMyRailData();
    },
    connectData: function () {
      this.railWithTitleView.setData(this.data);
    }
  }
});

In RailWithTitleView, implement a function setData.

Note

We also have to implement a convert. The more data youโ€™ll give the nativeRailElement, the slower it will get. This is why it is recommended to convert data before providing it to the nativeRailElement.

In a nutshell, know what you provide to the NativeRailElement.setData.


export default $View.declare("RailWithTitleView", {
  methods: {
    setData: function (data, options) {
      this.title.text = data.railName;
      this.list.setData(this.__convertDataToListModel(data.listData));
    },
    __convertDataToListModel: function (data) {
      const listModelData = [];
      data.forEach(content => {
        if (!content) {
          return;
        }
        listModelData.push({
          name: content.name,
          imageUrl: content.getImageUrl && content.getImageUrl({height: 185, ratio: content.ratio}),
          ratio: content.ratio
        });
      });
      return listModelData;
    }
    ,
  }
});

Enjoy !

Launch your UI with a grunt serve

:champagne_glass: Tadaa, you should see some rail being displayed on your rail.

Handling ok on the rail

In the screen, declare that you are listening to an event.

export default $AppScreen.declare("CatalogScreen", {
  listen: [
    $NativeRailElement.onItemClicked,
  ]
});

Then in the method of the screen declare onNativeRailElementItemClicked:

Caution

The name of the function matters as it is generated based on the name of the listener name.

export default $AppScreen.declare("CatalogScreen", {
  methods: {
    // Route to the fip for example
    // The clicked item will be available in data.item
    // You can also have the index of the item, in data.index
    onNativeRailElementItemClicked: function (data) {
      this.route("fipContent", {
        name: data.item.name,
        description: data.item.description,
        imageUrl: data.item.backgroundUrl,
        textGenres: data.item.genres.join(","),
        releaseYear: data.item.releaseYear
      });
    }
  }
});

Note

The data item that you receive will be one that you provided. You will need to add some info in the converter to receive the right info in the onClick listener.

Modifying other component depending on the focused view

We want to change the blue text to display info of the focused content when the rail is moved forward or backward. Native rail with focus behaviour

In the screen, declare that you are listening to an event.

export default $AppScreen.declare("CatalogScreen", {
  listen: [
    $NativeRailElement.onItemClicked,
    $NativeRailElement.onScroll
  ],
});

Then in the method of the screen declare onNativeRailElementScroll:

Caution

The name of the function matters as it is generated based on the name of the listener name.

export default $AppScreen.declare("CatalogScreen", {
  methods: {
    onNativeRailElementScroll: function (data) {
      // Access another view of the screen to be updated
      // Example
      return this.contentView.setAdditionnalContent(data.backgroundImageUrl)
    }
  }
});