user1949561
user1949561

Reputation: 187

AngualrJS 1.3 manually update binding with one time binding

I want to use one-time binding in my view {{::vm.list}}. That's all working well and good. However on a button click I want vm.list to refresh.

I can't seem to figure out how to manually trigger vm.list to update. Perhaps one time binding is not the answer?

here is a jsfiddle boilerplate example: http://jsfiddle.net/KamelJabber/e4nexvay/2/

(function () {
    var c1 = function Controller1() {
        var vm = this;
        var addCount = 1;
        vm.list = [{
            Id: 1,
            Text: "Blue One"
        }, {
            Id: 2,
            Text: "Blue Two"
        }, {
            Id: 3,
            Text: "Blue Three"
        }];

        vm.AddnRefresh = function () {
            vm.list.push({
                Id: vm.list.length,
                Text: "Add " + addCount
            });
            addCount++;

            //force a refresh of vm.list
        }
    };

    var app = angular.module('myApp', []);

    app.controller('Controller1', c1);
})();
<style> </style> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js"></script>
<div ng-app="myApp">
    <div ng-controller="Controller1 as vm">
        <p>
            <input type="button" ng-click="vm.AddnRefresh();" value="Add" />
        </p>
        <div ng-repeat="l in ::vm.list">{{::l.Text}}</div>
        <p></p>
        <div>LOTS of other stuff going on causing digest updates so really don't want to update list unless "Add" is called"</div>
    </div>
</div>

Upvotes: 11

Views: 3187

Answers (3)

Karanvir Kang
Karanvir Kang

Reputation: 2239

Angular will re-render the view if the parent DOM element is re-created. You can use a combination of ng-if, scope variable and $timeout service to achieve this:

View:

<div ng-if="!vm.status.reqRefresh">
     <div ng-repeat="l in ::vm.list">{{::l.Text}}</div>
</div>

Controller:

vm.status = {
    reqRefresh : false
};

vm.AddnRefresh = function () {
    vm.list.push({
        Id : vm.list.length,
        Text : "Add " + addCount
    });
    addCount++;

    //force a refresh of vm.list
    vm.status.reqRefresh = true;
    $timeout(function () {
        vm.status.reqRefresh = false;
    });
}

See updated fiddle here: http://jsfiddle.net/karank007/e4nexvay/143/

Upvotes: 3

user1364910
user1364910

Reputation:

I'm late to the party but I'll pitch in nevertheless.

I've been working on a notifier module for some time now and it's finally reached a 1.0.0 state where I feel I can start recommending it.

angular-bind-notifier

You could use this in two ways;

  1. Setup a watcher for a single property to update multiple bindings.
  2. $broadcast events manually to refresh a one-time binding.

I reckon #2 would be the best way to fulfill what you're looking for and that would go something like this:

<input type="button" ng-click="vm.AddnRefresh();" value="Add" />

<div ng-repeat="l in :refresh:vm.list">
  {{::l.Text}}
</div>

Notice the refresh that's been added between your one-time colons. This is the key you will utilise when wanting to trigger a refresh of the data.

All you need to do now is to update the AddnRefresh method like so:

vm.addnRefresh = function () {
  /** original implementation **/
  $scope.$broadcast('$$rebind::refresh'); // where 'refresh' is the key used in the view. 
};

$$rebind:: is the internal event namespace used by angular-bind-notifier.

And there you go - your view is now updated.


Here's a jsBin showcasing both ways of updating (1 $watcher & manual $broadcast).

Upvotes: 5

AngularLover
AngularLover

Reputation: 364

Hay you have to use the $scope to see the updated view. I've just added the vm in to a Scope. Here is the code:

  (function () {
    var c1 = function Controller1($scope) {
       $scope.vm = this;
        var addCount = 1;
        $scope.vm.list = [{
            Id: 1,
            Text: "Blue One"
        }, {
            Id: 2,
            Text: "Blue Two"
        }, {
            Id: 3,
            Text: "Blue Three"
        }];

       $scope.vm.AddnRefresh = function () {
            $scope.vm.list.push({
                Id: $scope.vm.list.length,
                Text: "Add " + addCount
            });
            addCount++;

            //force a refresh of vm.list
        }

    };

    var app = angular.module('myApp', []);

    app.controller('Controller1', c1);
})();

You also have to remove the :::

<div ng-app="myApp">
    <div ng-controller="Controller1 as vm">
        <p>
            <input type="button" ng-click="vm.AddnRefresh();" value="Add" />
        </p>
        <div ng-repeat="l in vm.list">{{::l.Text}}</div>
        <p></p>
        <div>LOTS of other stuff going on causing digest updates so really don't want to update list unless "Add" is called"</div>
    </div>
</div>

Upvotes: -1

Related Questions