最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - $watchCollection is not triggered - Stack Overflow

programmeradmin4浏览0评论

i have the following directive:

    app.directive('rickshawChart', function()
{
    return{
        $scope: {
            data: '=',
            renderer: '='
        },
        template: '<div></div>',
        restrict: 'E',
        link: function postLink(scope, element, attrs)
        {
           scope.$watchCollection('[data,renderer]', function(newVal, oldVal)
           {
                if(!newVal[0])
                {
                    return;
                }
               var graphEl = element.find("div:first");
               graphEl.html('');
               var graph = new Rickshaw.Graph({
                   element: graphEl[0],
                   width: attrs.width,
                   height: attrs.height,
                   series: [{data: scope.data, color: attrs.color, name: attrs.series}],
                   renderer: scope.renderer
               });
               graph.render();
           });
        }

    }
});

With the following html:

<rickshaw-chart
        data="sightingByDate"
        color="green"
        renderer="renderer"
        width="100%"
        height="100%">
</rickshaw-chart>

Here i fill the data in with the following controller:

    app.controller('CompetenceController', ['$http', '$scope','$sessionStorage','$log','Session','api',  function ($http, $scope, $sessionStorage,$log, Session, api) {

    $scope.result =[ { x: 0, y: 40 }, { x: 1, y: 49 }, { x: 2, y: 38 }, { x: 3, y: 30 }, { x: 4, y: 32 } ];
    $scope.renderer = 'scatterplot';
    $scope.sightingsByDate = _($scope.result)
        .chain()
        .countBy(function(sighting){
            return sighting.y;
        })
        .pairs()
        .map(function(pair){
            return pair;
        })
        .value();
}]);

however from the debugger i am able to see that the $watchCollection is never executed.

What am i doing wrong?

i have the following directive:

    app.directive('rickshawChart', function()
{
    return{
        $scope: {
            data: '=',
            renderer: '='
        },
        template: '<div></div>',
        restrict: 'E',
        link: function postLink(scope, element, attrs)
        {
           scope.$watchCollection('[data,renderer]', function(newVal, oldVal)
           {
                if(!newVal[0])
                {
                    return;
                }
               var graphEl = element.find("div:first");
               graphEl.html('');
               var graph = new Rickshaw.Graph({
                   element: graphEl[0],
                   width: attrs.width,
                   height: attrs.height,
                   series: [{data: scope.data, color: attrs.color, name: attrs.series}],
                   renderer: scope.renderer
               });
               graph.render();
           });
        }

    }
});

With the following html:

<rickshaw-chart
        data="sightingByDate"
        color="green"
        renderer="renderer"
        width="100%"
        height="100%">
</rickshaw-chart>

Here i fill the data in with the following controller:

    app.controller('CompetenceController', ['$http', '$scope','$sessionStorage','$log','Session','api',  function ($http, $scope, $sessionStorage,$log, Session, api) {

    $scope.result =[ { x: 0, y: 40 }, { x: 1, y: 49 }, { x: 2, y: 38 }, { x: 3, y: 30 }, { x: 4, y: 32 } ];
    $scope.renderer = 'scatterplot';
    $scope.sightingsByDate = _($scope.result)
        .chain()
        .countBy(function(sighting){
            return sighting.y;
        })
        .pairs()
        .map(function(pair){
            return pair;
        })
        .value();
}]);

however from the debugger i am able to see that the $watchCollection is never executed.

What am i doing wrong?

Share Improve this question asked Apr 2, 2015 at 9:21 Marc RasmussenMarc Rasmussen 20.6k83 gold badges223 silver badges384 bronze badges 1
  • Ping check my aswer :) – squiroid Commented Apr 2, 2015 at 9:47
Add a ment  | 

3 Answers 3

Reset to default 6

You should use the $watch expression with true as a third parameter:

scope.$watch('[data,renderer]', function (newVal, oldVal) {
         //code
 }, true);

$watchCollection doesn't work for you because you have both an array and a property. In this case is like you're checking contemporarily $scope.$watch('data' and $scope.$watch('renderer'. And if a property in the array changes, the event will not trigger.

There are four types of $watch:

  1. the simpliest is $watch, it simply check if the property or the whole object changed
  2. the second is $watchCollection which watches if any property within an array changed (in your case this doesn't work, because you have both an array and a property)
  3. the third is $watchGroup (since 1.3) which is the most recent version of $watchCollection, which allows you to check an array of expressions (but the same could be achieved with $watchCollection as you were trying to do
  4. $watch('object', function(){...}, true). This check if every single property changed within an object

This is a simplified version of your code, if you press the change value button, you can see how an element in the array is changed and how the event is triggered in the console: http://jsfiddle/27gc71bL/

EDIT: I forgot to add something in my answer. I think there's a typo in your code, you are creating a directive using:

        $scope: {
            data: '=',
            renderer: '='
        },

This is not creating a new scope within the directive. So when you are using scope.data in the link function, you are referring to the $scope.data of the parent (the controller).

What I think you wanted, is to create a new scope in this way:

        scope: {
            data: '=',
            renderer: '='
        },

and, in your controller, bind the array you want to check to sightingByDate.

As doc said

Shallow watches the properties of an object and fires whenever any of the properties change (for arrays, this implies watching the array items; for object maps, this implies watching the properties). If a change is detected, the listener callback is fired.

Watch collection is used for shallow copy of object and array only :) And in your case both things are just value not array or object.

So I guess you need $watchGroup for your work to be done.

$scope.$watchGroup(['teamScore', 'time'], function(newVal, oldVal) {.. }

The code looks correct as long as somewhere either sightingByDate or renderer is getting modified. Perhaps, this is not evident in your code snippet. Make sure any or both of these are getting changed somewhere in your flow to trigger WatchCollection

发布评论

评论列表(0)

  1. 暂无评论