3

Let's say I have 2 directives: "parent" (i.e. table) and "child" (tr), I would like to be able to select child elements and keep the list of them in my parent directive (I think the controller is the only possible place, isn't it?). I'm handling click events to update the list stored in my controller and it works fine but I'd also like to keep "selected" class for selected items, but because the selection may also be changed by the controller of parent directive (and modifying the DOM in controller is "forbidden"), the only possibility I could think of is a watcher in my child directive.

Take a look at the example, please:

angular.module('App')
    .directive('parent', function () {
    return {
        scope : {},
        controller: function($scope) {
            this.selectedItems = [];
        }
    }
}).directive('child', function() {
    return {
        require: '^parent',
        link: function(scope, element, attrs, controller) {
            scope.$watchCollection('controller.selectedItems', function() {
                //add or remove 'selected' class here.
            }
        }
    }
});

That doesn't work (the watcher event fires only when the array reference changes and not individual elements) and it doesn't seem to be designed correctly either, could you provide me with a better approach to that issue?

update:

Notice that controller.selectedItems is modified in the controller, however the child directive does not seems to watch any change.

morels
  • 2,095
  • 17
  • 24

2 Answers2

2

I fixed it with invoking $scope.$apply() after modifying the array in controller. Methods were triggered by javascript events so the digest loop was never run probably.

If anyone had other suggestions related to the above design, please let me know.

  • Obviously. If a variable is modified by a controller but watched somewhere else, if there is not $digest or $apply the watcher does not see any change. So the problem was somewhere else. In your OP there was come code missing in order to understand fully the problem! – morels Oct 20 '15 at 07:27
  • Yea, that's true. Thank you very much for help ! – Andrzej Czerwoniec Oct 20 '15 at 07:52
1

Pls see: How to deep watch an array in angularjs?

You should use $watch and set the third optional argument of $watch to true.

        scope.$watch(function(){
            return controller.selectedItems;
            },
            function() {
            //add or remove 'selected' class here.
            },
            true
        );

update:

Okay so you should also notify all application external watchers that a modification has took place. In AngularJS if a variable is modified by a controller but watched somewhere else and if there is not $digest or $apply the watcher does not see any change. So the problem was not the choice of the watcher, but the missing of an $apply command.

Simply add:

$scope.$apply();

in your controller after the alteration of the array.

Community
  • 1
  • 1
morels
  • 2,095
  • 17
  • 24
  • Angular provides a $watchCollection for that so I think I shouldn't have to use deep watch and it doesn't work either - it still fires only when the reference changes – Andrzej Czerwoniec Oct 19 '15 at 13:10
  • What is the content of selectedItems? Is an array of simple values or objects? In the second case you need to deep watch it. Anyway I used `function(){ return controller.selectedItems; }` because usually giving `controller.selectedItems` does not function. – morels Oct 19 '15 at 13:20
  • It's the array of objects but I don't want to know about changes in individual objects but about changes in the array - removed / added items. So for example whenever new item is added to this array I want to trigger event. – Andrzej Czerwoniec Oct 19 '15 at 13:25
  • so why don't watch the size of the array? – morels Oct 19 '15 at 13:26
  • I store them at indexes corresponding to their real position because I need that position later, so that array may look like [obj, , , , , obj], and the next item may be added on the 3rd index or so. – Andrzej Czerwoniec Oct 19 '15 at 13:30