Notifying change with ES5 getter and setter

Thread is closed for posting
4 posts, 0 answers
  1. Richard
    Richard avatar
    8 posts
    Member since:
    Feb 2013

    Posted 29 Mar 2015 Link to this post

    I'm experimenting on how I can restructure my NativeScript app using typescript. The first version of the application used the observable object as it is and everything was working fine. I tried  restructuring the code by moving the view model to a different class that wraps around the observable object. The thing is that values are set just fine from the UI but it appears setting the value from code does not change the UI. The idea is to encapsulate everything in the view model and use the generated object like any javascript object without using .get and .set.

    MainViewModel.ts
    import observableModule = require("data/observable");
    import observableArrayModule = require("data/observable-array");
    import Utils = require("../lib/Utils");
     
    export interface ITask { name: string; }
     
    export class ViewModel {
        private observable = new observableModule.Observable();
     
        constructor(json?: any) {
            this.init();
            if (json)
                for (var key in json)
                    this.observable.set(key, json[key]);
        }
        private init() {
            this.observable.set('task', '');
            this.observable.set('tasks', new observableArrayModule.ObservableArray());
        }
     
        public textFieldId = Utils.uniqueId("ui");
        public get task(): string {
            return this.observable.get('task');
        }
        public set task(value) {
            this.observable.set('task', value);
        }
        public get tasks(): observableArrayModule.ObservableArray<ITask> {
            return this.observable.get('tasks');
        }
        public set tasks(value) {
            this.observable.set('tasks', value);
        }
        public addTask(task: ITask) {
            this.tasks.push(task);
        }
    }


    Main.ts
    import viewModule = require("ui/core/view");
    import textFieldModule = require("ui/text-field");
    import pageModule = require("ui/page");
    import frame = require("ui/frame");
    import model = require("./mainViewModel");
     
    var page: pageModule.Page;
    var vm = new model.ViewModel();
     
    export function onPageLoaded(args) {
        page = args.object;
        page.bindingContext = vm;
        if (frame.topmost().android) {
            frame.topmost().android.actionBar.hide();
        }
    }
      
    export function add() {
        vm.tasks.push({ name: vm.task });
        vm.task = "";
        var view = viewModule.getViewById<textFieldModule.TextField>(page, vm.textFieldId);
        view.dismissSoftInput();
    }

    Main.xml
    <Page loaded="onPageLoaded">
      <GridLayout rows="auto,*">
        <StackLayout orientation="horizontal" row="0">
          <TextField width="200" text="{{task}}" hint="Enter a task" id="{{textFieldId}}"/>
          <Button text="Add" tap="add"></Button>
        </StackLayout>
     
        <ListView items="{{tasks}}" row="1">
          <ListView.itemTemplate>
            <Label text="{{name}}" />
          </ListView.itemTemplate>
        </ListView>
      </GridLayout>
    </Page>


    When the add function is called after a button is clicked, the list of items increase but the textbox is not cleared when I set that task property to an empty string.

    I did try simply inheriting from observable instead of having a local copy but that caused the application to hang anytime I run it. Very sure I did not implement it well.

    What do I do to get the two way binding to work? Am I approaching this wrongly? If so, what is the right way to go around this?




  2. Richard
    Richard avatar
    8 posts
    Member since:
    Feb 2013

    Posted 30 Mar 2015 Link to this post

    I exposed the internal observable and used it for the binding and now the ui updates correctly. I guess the question now therefore is how do I make NativeScript create my custom class like an observable that can participate in two way binding?
  3. Richard
    Richard avatar
    8 posts
    Member since:
    Feb 2013

    Posted 30 Mar 2015 Link to this post

    After looking around the source code (bindable.js), I realized that the event listeners are only registered when the source is an instance of observable. Anything else is ignored.

    I changed it from
    if (sourceOptionsInstance instanceof observable.Observable) {

    to
    if (sourceOptionsInstance.addEventListener && sourceOptionsInstance.removeEventListener) {

    Is there any reason for the current behavior? Is there another way of getting this to work without change code in the main libraries?
  4. Erjan Gavalji
    Admin
    Erjan Gavalji avatar
    1455 posts

    Posted 03 Apr 2015 Link to this post

    Hi Richard,

    How about inheriting the Observable class, e.g.

    export class ViewModel extends observableModule.Observable {
    ...
    }

    Kind regards,
    Erjan Gavalji
    Telerik
     

    See What's Next in App Development. Register for TelerikNEXT.

     
Back to Top