2
votes

I want to create a dynamic menu list, and apply class at selected item. I have an array of menu entries, menuItems which is an observableArray.

The page binding contain two entries :

  • menuItems
  • selectedPage

console.log(page.bindingContext)

The idea is simple : apply a different class when the selectedPage parameter equal the page name to indicate to user which page is currently displayed.

<Repeater items="{{menuItems}}" id="repeater">
  <Repeater.itemTemplate>
    <Label text="{{name}}" class="{{ $parents['Page'].selectedPage == name ? 'selected' : '' }}" tap="navigate" />
  </Repeater.itemTemplate>
</Repeater>

This doesn't work, so I have made some tests, and a strange thing happened. When I use a simple Label into my Repeater to test my bindings, I can acces the good datas.


<Label text="{{name}}"/>

Display the good menuItems entry name.


<Label text="{{$parents['Page'].selectedPage}}"/>

Display the good selectedPage entry name.


But, these code samples doesn't work together. Both works only independently.

So, I'm a bit lost, is using a $parents based selector change the context inside the Repeater ?

1

1 Answers

1
votes

I too have encountered this issue and found the solution in NativeScript's documentation on data binding:

Note: Binding expression could be used without explicitly named source property ( TextField text="" ). In that case $value is used as a source property. However this could lead to problems when a nested property should be observed for changes (e.g. item.nestedProp). $value represents bindingContext and when any property of the bindingContext is changed expression will be evaluated. Since nestedProp is not a property of the bindingContext in item.nestedProp then there will be no propertyChange listener attached and changes to nestedProp will not be populated to UI. So it is a good practice to specify which property should be used as source property in order to eliminate such issues.

What this means is that when you're binding a variable that's set directly on your binding context, you can pass the expression into the curly brackets by itself:

    <Label text="{{name}}" class="{{ mySelectedPage == name ? 'selected' : '' }}" tap="navigate" />

...but if you're binding a variable that's nested within an object which is set on the binding context, you must pass that nested property into the curly brackets as the first parameter, and the expression itself as the second parameter:

<Label text="{{name}}" class="{{ $parents['Page'].selectedPage, $parents['Page'].selectedPage == name ? 'selected' : '' }}" tap="navigate" />