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.

1
  • added the fixing solution according to your feedback. Commented Oct 21, 2015 at 9:35

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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!
Yea, that's true. Thank you very much for help !
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.

5 Comments

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
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.
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.
so why don't watch the size of the array?
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.