Aaron Ullal
Aaron Ullal

Reputation: 5245

Nativescript Observable not binding

I am trying to bind the visibility property of a list of images to an array.

Here is what I have:

XML MARKUP

<GridLayout id="menu">
        <Image src="{{ ... }}" tap="menuItemTap" id="explore" visibility="{{ menuItemsArray[0].visibility }}" />
        <Image src="{{ ... }}" tap="menuItemTap" id="community" visibility="{{ menuItemsArray[1].visibility }}"/>
        <Image src="{{ ... }}" tap="menuItemTap" id="profile" visibility="{{ menuItemsArray[2].visibility }}"/>
        <Image src="{{ ... }}" tap="menuItemTap" id="ranking" visibility="{{ menuItemsArray[3].visibility }}"/>
        <Image src="{{ ... }}" tap="menuItemTap" id="camera" visibility="{{ menuItemsArray[4].visibility }}"/>
    </GridLayout>

As you can see , I am binding visibilityto the menuItemsArray, which is part of an Observable defined as the following:

OBSERVABLE

mainObservable = new Observable({
    currentActive:"explore",
    menuItemsArray:[
        new MenuItem("explore"),
        new MenuItem("community"),
        new MenuItem("profile"),
        new MenuItem("ranking"),
        new MenuItem("camera")
    ]
});

menuItemsArray is an array of MenuItem objects , which have 2 properties : name and visibility, the latter being bound to the images.

EDIT I hereby also post the MenuItem class

MenuItem

var menuitem = function(name,visibility){
    var _name = name;
    var _visibility = visibility || "collapsed" ;
    Object.defineProperty(this,"visibility",{
            get : function(){
                return _visibility;
            },
            set : function(visibility){
                _visibility = visibility;
                console.log("called set-> visibility to " + _visibility);
            }
        });
    Object.defineProperty(this,"name",{
        get : function(){
            return _name;
        },
        set : function(name){
            _name = name;
        }
    })
}

As per @peterstaev's suggestion I also tried the following:

MenuItem

class MenuItem extends Observable{
    constructor(name,visibility){
        super();
        this._name = name;
        this._visibility = visibility || "collapsed";

    }
    get visibility(){
        return this._visibility;

    }
    set visibility(visibility){
        this._visibility = visibility;
        console.log("called set-> visibility to " + this._visibility);
    }
    get name(){
        return this._name;
    }
    set name(name){
        this._name = _name;
    }
};
module.exports = MenuItem;

Interestingly visibility is set to "collapsed" per default, and , in fact, none of the images show up (which is the desired behavior). However if switch visibility to "visible" - mainObservable.menuItemsArray[0].visibility = "visible" - it doesn't affect the image, as it won't display. What is causing this issue? Am I improperly using the Observable ?

Upvotes: 1

Views: 485

Answers (2)

Nick Iliev
Nick Iliev

Reputation: 9670

Here is my approach to your senario :

in page.xml

<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
    <DockLayout id="menu">
        <ListView items="{{ menuItems }}"  loaded="onLoaded" itemLoading="onItemLoading" itemTap="onItemTap">
            <ListView.itemTemplate>
                <StackLayout>
                    <Image src="res://icon" stretch="none" visibility="{{ $value.visibility ? 'visible' : 'collapsed' }}" />
                </StackLayout>
            </ListView.itemTemplate>
        </ListView>
    </DockLayout>
</Page>

in page.js

"use strict";
var observable_1 = require("data/observable");
var observable_array_1 = require("data/observable-array");

var MenuItem = (function (_super) {
    __extends(MenuItem, _super);
    function MenuItem(name) {
        _super.call(this);
        this._name = name;
        this._visibility = false;
    }

    Object.defineProperty(MenuItem.prototype, "name", {
        get: function () {
            return this._name;
        },
        set: function (value) {
            this._name = value;
        },
        enumerable: true,
        configurable: true
    });

    Object.defineProperty(MenuItem.prototype, "visibility", {
        get: function () {
            return this._visibility;
        },
        set: function (value) {
            this._visibility = value;
            this.notifyPropertyChange("isVisible", value);
        },
        enumerable: true,
        configurable: true
    });
    return MenuItem;
}(observable_1.Observable));

var itemsObservableArray = new observable_array_1.ObservableArray([
    new MenuItem("explore"),
    new MenuItem("community"),
    new MenuItem("profile"),
    new MenuItem("ranking"),
    new MenuItem("camera")
]);

var viewModel = new observable_1.Observable({
    currentActive: "explore",
    menuItems: itemsObservableArray
});

function navigatingTo(args) {

    var page = args.object;
    itemsObservableArray.getItem(0).set("visibility", true);
    itemsObservableArray.getItem(1).set("visibility", true);
    itemsObservableArray.getItem(2).set("visibility", true);
    page.bindingContext = viewModel;
}
exports.navigatingTo = navigatingTo;

Upvotes: 0

Peter Staev
Peter Staev

Reputation: 1119

When you change the visibility you should use the set method of the observable so it correctly notifies bound object for changes. So you should be using:

mainObservable.menuItemsArray[0].set("visibility", "visible");

Upvotes: 2

Related Questions