Home angularjs $scope.$watchCollection on nested JSON document
Reply: 1

angularjs $scope.$watchCollection on nested JSON document

Dr. Frank Fox
1#
Dr. Frank Fox Published in 2017-11-14 16:23:38Z

I'm having troubles with the $watchCollection() function. The problem might be the fact that I'm trying to reference a nested part of a JSON document. I really can't figure the problem out.

HTML

<div ng-app="MovieApp">
  <div ng-controller="FilterController as FilterCtrl" ng-init="FilterCtrl.init()">
    <ul ng-repeat="filter in filters">
      <b>{{filter.name}}</b>
      <li ng-repeat="element in filter.elements">
        <input type="checkbox" ng-model="element.ticked" />{{element.name}}
      </li>
    </ul>
  </div>
</div>

JS

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

app.controller('FilterController', function($scope){
  this.init = function(){
    $scope.filters = jsonfilters;
  };

  $scope.$watchCollection('filters', function(newValue,oldValue){
    alert("A filter has been changed");
  });

});

var jsonfilters = [
{
  "name": "Genres",
  "elements": [
    {"name": "Adventure", "ticked": true},
    {"name": "Action", "ticked": true},
    {"name": "Fantasy", "ticked": true},
    {"name": "Science Fiction", "ticked": true},
    {"name": "Family", "ticked": true},
    {"name": "Thriller", "ticked": true},
    {"name": "Animation", "ticked": true},
    {"name": "Comedy", "ticked": true},
    {"name": "Drama", "ticked": true}
  ]
},
{   
  "name": "Companies",
  "elements": [
    {"name": "Warner Bros.", "ticked": true},
    {"name": "Walt Disney Pictures", "ticked": true},
    {"name": "Paramount Pictures", "ticked": true},
    {"name": "Columbia Pictures", "ticked": true},
    {"name": "DreamWorks Animation", "ticked": true},
    {"name": "Universal Pictures", "ticked": true},
    {"name": "Twentieth Century Fox Film Corporation", "ticked": true},
    {"name": "Legendary Pictures", "ticked": true},
    {"name": "Marvel Studios", "ticked": true},
    {"name": "Village Roadshow Pictures", "ticked": true},
    {"name": "Jerry Bruckheimer Films", "ticked": true}
  ]
}
];

What I want to achieve is being able to call a function everytime one of the checkboxes are ticked/unticked. I made a jsfiddle to demo the problem.

Intervalia
2#
Intervalia Reply to 2017-11-15 16:59:11Z

If you don't need $watchCollection, I suggest avoiding it. There is a large cost to using it, aside from the fact that you didn't get it to work.

Instead try using an event to let you know what changed.

I am using the ng-change directive to know when the user clicks on a checkbox.

HTML

<div ng-app="MovieApp">
  <div ng-controller="FilterController as FilterCtrl" ng-init="FilterCtrl.init()">
    <ul ng-repeat="filter in filters">
      <b>{{filter.name}}</b>
      <li ng-repeat="element in filter.elements">
        <input type="checkbox" ng-model="element.ticked" ng-change="filterChanged($event, element)" />{{element.name}}
      </li>
    </ul>
  </div>
</div>

JS

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

app.controller('FilterController', function($scope){
  this.init = function(){
    $scope.filters = jsonfilters;
  };

    $scope.filterChanged = function($event, element) {
    console.log('Filter changed:', element);
  }
});

var jsonfilters = [
  {
    "name": "Genres",
    "elements": [
      {"name": "Adventure", "ticked": true},
      {"name": "Action", "ticked": true},
      {"name": "Fantasy", "ticked": true},
      {"name": "Science Fiction", "ticked": true},
      {"name": "Family", "ticked": true},
      {"name": "Thriller", "ticked": true},
      {"name": "Animation", "ticked": true},
      {"name": "Comedy", "ticked": true},
      {"name": "Drama", "ticked": true}
    ]
  },
  { 
    "name": "Companies",
    "elements": [
      {"name": "Warner Bros.", "ticked": true},
      {"name": "Walt Disney Pictures", "ticked": true},
      {"name": "Paramount Pictures", "ticked": true},
      {"name": "Columbia Pictures", "ticked": true},
      {"name": "DreamWorks Animation", "ticked": true},
      {"name": "Universal Pictures", "ticked": true},
      {"name": "Twentieth Century Fox Film Corporation", "ticked": true},
      {"name": "Legendary Pictures", "ticked": true},
      {"name": "Marvel Studios", "ticked": true},
      {"name": "Village Roadshow Pictures", "ticked": true},
      {"name": "Jerry Bruckheimer Films", "ticked": true}
    ]
  }
];

See my jsfiddle here: https://jsfiddle.net/intervalia/5k7ehswt/2/

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.305609 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO