Search code examples
javascriptangularjsangular-servicesangular-directive

How to update directives based on service changes?


I have a directive(parent-directive) containing a slider(mySlider), that on stop event, call an angular $resource service with 2 params and the service return an object. Directives structure:

<parent-directive>
<div ui-slider="slider.options" ng-model="mySlider" id="my-slider">
<span child-directive-one></span>
<span child-directive-two></span>
<span child-directive-three></span>
<div>
    <span child-directive-four></child-directive-four>
</div>
</parent-directive

Whenever the user drag the slider, the service is called with different params and retieve new result, based on it I need to update the child directives.

I have in mind three ways:

  1. using ng-model for all child elements instead directives, binding them on the scope of a controller in parent-directive;
  2. the second one, that I don't know how to do it, is to create a controller in the parent-directive, that send and receive data from the service and share it to child-directives in order to update them.
  3. the last one is to to create a state variable in the service and update it using a controller like to point 1.(see it above) and use a $watch to supervise the variable state and when it's changed then update the child-directives.

How should I proceed?

Please have a look here to see a brief code: http://jsfiddle.net/v5xL0dg9/2/

Thanks!


Solution

    1. ngModel is intended for two way binding, i.e. controls that allow the user to interfere with the value. From the description, it seems they are display-only components. So I would advise against using the ngModel.

    2. Normally child directives require their parent. This allows them to call methods on the parent controller. What you need is the opposite: the parent controller needs to call methods on the children. It can be done: the children call a registerChild() method, and the parent iterates all registered children when it needs to call them. I find this implementation cumbersome.

    3. Services are globals/singletons. I would vote against tying the service implementation to the UI needs.

    My advice looks like your implementation of option 3, but with the parent controller holding the data:

    1) Place the data you want to share with the child directives in a member variable of the parent controller:

    myApp.directive('parentDirective', ['myService', function(myService){
        ...
        controller: function($scope) {
            ...
            this.sharedThing = ...;
        }
    }]);
    

    The sharedThing can be updated when the service returns new data, or any other time it is necessary.

    2) Have the children require the parent (just like your option 2), and watch this property:

    myApp.directive('childDirectiveOne', function() {
        return {
            ...
            require: 'parentDirective',
            link: function(scope, elem, attrs, parentDirective) {
                scope.$watch(
                    function() {
                        return parentDirective.sharedThing;
                    },
                    function(newval) {
                        // do something with the new value; most probably
                        // you want to place it in the scope
                    }
                });
            }
        };
    });
    

    Depending on the nature of the data, a deep watch may be required.