Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS start watch after loading content

Tags:

angularjs

im new in AngularJS. Trying create first app, and have problem. Have list of checkboxes

<div class='order-box row-fluid' ng-repeat="order in orders" ng-model="orders">
   <input type="checkbox" value="{{ order.id }}" ng-model="order.selected">
<div>

orders is filling from server by ajax query on load page.

function OrdersCtrl($scope, Order){
    $scope.orders = Order.query();
    $scope.$watch('orders', function(v){
        if (!v) return;
        alert(v);
    }, true);
}

Primary target is calculate cost by selected checkboxes.

But on load page i see alerts, how start watch only after load content?

Second litle question: Have ng-repeat on div. And all repeatet divs like

<div class="order-box row-fluid ng-scope ng-pristine ng-valid" ng-repeat="order in orders" ng-model="orders">

Is it normal?

like image 595
Actimele Avatar asked Jul 24 '13 23:07

Actimele


2 Answers

Try add a flag, or try it on jsfiddle link.

function OrdersCtrl($scope, $timeout) {
    $scope.orders = [];
    var first = true; //this doesn't belong to any scope, it will be deallocated after the current cycle.

    var ajax = function () {
        $scope.orders = [{
            id: 1,
            selected: true
        }, {
            id: 2,
            selected: true
        }, {
            id: 3,
            selected: true
        }, {
            id: 4,
            selected: true
        }];
    };

    $scope.$watch('orders', function (n, o) {
        if (first) {
            $timeout(ajax, 2000); //simulate the ajax call. Assume data comes back in 2 seconds.
        } else {
            alert(n);
        }
    });
}
like image 121
zs2020 Avatar answered Sep 21 '22 16:09

zs2020


  1. There is no way to avoid the first call; You have to use a flag to skip that one.
  2. There will always be a 2nd call too. That is when the orders gets populated. To avoid that one, you can check if oldVal is an empty array.
  3. I think you should watch the selected property; not all properties of an order.
  4. The watch should compare values, not instances; hence the true param on $watch

Here is the code with a custom watch function:

// watch only order.selected
var watch = function(o) {
  var mapped = _.map(o.orders, function(o){
    return o.selected || false;
  });
  return mapped; 
};

var firstWatch = true;
$scope.$watch(watch, function(newVal, oldVal) {
  if ( firstWatch || oldVal.length === 0 ) {
      firstWatch = false;
      return;
  }
  console.log('changed', newVal, oldVal);
}, true);

See this example : http://plnkr.co/edit/q29mXXcdHRYHG9frvfNC?p=preview. There is nothing logged to the console until you actually check an item.

like image 42
Sylvain Avatar answered Sep 23 '22 16:09

Sylvain