NativeScript bind to array with variable index

Category: #nativescript

Context

Let’s say you are in a situation where you want to show the user the corresponding image when the user selects a particular option in NativeScript Core. We’ll use the <Image> widget to display the image, and <SegementedBar> to display the options.

Initial Setup

      <Page loaded="pageLoaded" unloaded="pageUnLoaded" class="page" xmlns="http://www.nativescript.org/tns.xsd">
        <ActionBar title="Binding to array with variable index" class="action-bar">
        </ActionBar>
        <FlexboxLayout flexDirection="column" class="p-10">
          <Image width="50" src="https://play.nativescript.org/dist/assets/img/NativeScript_logo.png" />
          <Label class="h2 text-center" text="Flavors of NativeScript" />
          <SegmentedBar id="segmentedBar">
            <SegmentedBar.items>
              <SegmentedBarItem title="{N} - JS" />
              <SegmentedBarItem title="{N} - TS" />
              <SegmentedBarItem title="{N} - NG" />
              <SegmentedBarItem title="{N} - Vue" />
            </SegmentedBar.items>
          </SegmentedBar>
          <!-- Bind the label to `index`th element in the `text` array -->
          <Label class="h3 m-10 text-center" text="" />
          <!-- Bind the src to `index`th element in the `images` array -->
          <Image width="250" src="" />
        </FlexboxLayout>
      </Page>
    
home-page.js
      const HomeViewModel = require("./home-view-model");
      const homeViewModel = new HomeViewModel();

      exports.pageLoaded = (args) => {
        const page = args.object;
        page.bindingContext = homeViewModel;

        const segmentedBar = page.getViewById("segmentedBar");
        segmentedBar.on("selectedIndexChange", homeViewModel.onIndexChange);
      };

      exports.pageUnLoaded = (args) => {
        const page = args.object;
        const segmentedBar = page.getViewById("segmentedBar");
        segmentedBar.off("selectedIndexChange");
      };
    
home-view-model.js
      const observableModule = require("data/observable");

      function HomeViewModel() {
        const viewModel = observableModule.fromObject({
          index: 0,
          images: [
            'https://shiv19.com/assets/img/logos/js.png',
            'https://shiv19.com/assets/img/logos/ts.png',
            'https://shiv19.com/assets/img/logos/ng.png',
            'https://shiv19.com/assets/img/logos/vue.png'
          ],
          text: [
            'NativeScript with JavaScript',
            'NativeScript with TypeScript',
            'NativeScript with Angular',
            'NativeScript with Vue'
          ],
          onIndexChange(args) {
            viewModel.set('index', args.object.selectedIndex);
          }
        });

        return viewModel;
      }

      module.exports = HomeViewModel;
    

Note: At the time of writing this article it is not possible to bind to selectedIndexChange event from the xml file in NativeScript core.

Challenge

Before you proceed reading this further, try to do this yourself.

Here is the link to start code: https://play.nativescript.org/?template=play-js&id=tZVTxB

Did you manage to do it? If yes, well done! If no, read on!

Solution

The intuitive approach here would be to bind the text property to {{ text[index] }} and bind the src property to {{ src[index] }}

However, using multiple variables in an expression like that is not supported in NativeScript. So the way we bind is by specifying the different variables that we will be using, before using them in an expression.

So the correct way to bind it is, text="{{ text index, text[index] }}" for the label
src="{{ images index, images[index] }}" for the image
(Note: The order in which you specify the variables does not matter)

Here is the link to the completed code: https://play.nativescript.org/?template=play-js&id=LG7lHa

Let me know if you enjoyed this short tutorial on Twitter: @MultiShiv19, and what else you’d like to see in these tutorials.

Written on July 26, 2018