In Angular, is there a way to directive in a mandatory way?

What i know

I have a custom scoped directive.
From the "outside" I can pass the directive using declarative bindings (via @

and bindings =

).
A directive can bind to an external one using either declarative bindings ( =

) or mandatory callbacks ( &

).

What i would like to know

Is there a mandatory way to communicate with a directive ?

Example

Let's say I have a directive <edit-profile>

. I would like to expose the method reset()

so that the owner of the directive can reset the directive (imperatively).

Here's what I would like to do with it:

<edit-profile on-save="..."></edit-profile>
<button ng-click="editProfile.reset()"> Reset </button>

      

And here is my directive:

app.directive("editProfile", function() {
    return {
        restrict: "E",
        scope: {
            onSave: "&"
        },
        template: `
            <input type="text">
            <button ng-click="onSave()"> Submit </button>
        `,
        controller: function($scope) {
            $scope.reset = function(){ ... };
        }
    };
});

      

In what ways can I achieve this "imperative" approach to directive communication?

+3


source to share


2 answers


You can use the same technique as the 'form' directive: expose the directive controller to its parent scope. Here's a basic example:

angular.module('directives').directive('foo', function() {
    return {
        scope: {
            name: '='
        },
        controller: function($scope) {
            this.sayHello = function() {
                $scope.hello = 'hello';
            };
            $scope.name = this;
        },
        template: '<div>{{ hello }}</div>'
    };
});

      



And its a unit test showing how a reference outside of a directive can call a function on the controller when clicked:

describe('foo', function() {
    var elm, scope;

    beforeEach(module('directives'));

    beforeEach(inject(function($rootScope, $compile) {
        elm = angular.element(
            '<div><foo name="bar"></foo><a href="" ng-click="bar.sayHello()">say hello</a></div>');

        scope = $rootScope;
        $compile(elm)(scope);
        scope.$digest();
    }));

    it('should say hello', function() {
        var a = elm.find('a');
        var div = elm.find('foo');

        expect(div.text()).not.toContain('hello');

        a.triggerHandler('click');

        expect(div.text()).toContain('hello');

    });
});

      

+1


source


As far as I know, your parent scope won't know about any of the child scopes APIs unless you start walking down the scope hierarchy. But you can use events to do what you want. You can use the parent scope to broadcast down the scope hierarchy. This requires your child / directive space to listen for the event.

parentScope.$broadcast('eventName', arg1, arg2, arg3)

directiveScope.$on('eventName', function(event, arg1, arg2, arg3){ })

      

I would recommend that you stop the event from propagating further.



Check out these links:

+1


source







All Articles