7

How to call a method defined in child directive, within a button click listener of parent directive.

angular.module('editableDivDirective', [])

.directive("editableDiv", function() {
    var directive = {};
    directive.restrict = 'E';
    directive.replace = 'true';
    directive.scope = {};
    directive.transclude = 'true';
    directive.template =
        '<div id="wrapper">' +
            '<div required class="text-area" name="search" contenteditable="true" ng-model="formData.text"></div>' +
            '<button type="submit" class="btn btn-warning add-button" id="submit" ng-click="createTodo()">Add</button>' +
        '</div>';
    directive.link = function(scope, element, attrs, controller) {
        scope.createTodo = function(){
            // do something         
            // Call child directive setPlaceholderText()
        }
    };

    return directive;
})
.directive("contenteditable", function() {
    var directive = {};
    directive.require = ['^editableDiv','?ngModel'];
    directive.restrict = 'A';
    directive.scope = {};
    directive.link = function(scope, element, attrs, ctrls) {
        var ngModel = ctrls[1];
        var editableDivController = ctrls[0];

         function setPlaceholderText(){
            return element.html("Hello World");
        }

    return directive;
})

I want to call child directive setPlaceholderText() when 'scope.createTodo()' of parent directive is called.

How can that be done.

2
  • What is your specific use case? What have you tried? Commented Dec 18, 2014 at 19:12
  • @Patrick i have added more details. Sorry was away from my system so couldnt add that in time. Commented Dec 19, 2014 at 3:51

3 Answers 3

3

In your parent directive

link: function($scope,$el,$attr) {
    $el.find(".thing").on('click',function(event){
       $scope.$broadcast('thing', $scope.someData);
    });
}

In your child directive

link: function($scope. $el, $attr) {
    $scope.$on('thing',function(event, someData) {
       alert('My parent called me with this data: ' + someData);
    });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Mathew. Would this be applicable when the directives have isolated scope?
2

You can $broadcast an event to child scopes (as mentioned), or you can also add a function to your parent directive's controller from your child directive.

Here is a jsfiddle with examples of both $broadcast to child directive and using the controller technique.

angular.module("myApp", [])

.directive("parentDirective", function () {
    var directive = {};
    directive.restrict = "E";
    directive.scope = {};
    directive.template = '<div>' +
        '<button type="button" ng-click="broadcastDemo()">' +
            'Broadcast to child' +
        '</button>' +
        '<button type="button" ng-click="controllerDemo()">' +
            'Use Controller' +
        '</button><br /><br />' +
        '<child-directive></child-directive>';
    //Setup directive controller
    directive.controller = function ($scope) {
        var ctrl = this;
        //Store events for convenience
        var events = ctrl.events = {
            setPlaceHolderText: "setPlaceHolderTextEvent"
        };

        $scope.broadcastDemo = function () {
            //$broadcast event and optional additional args
            $scope.$broadcast(events.setPlaceHolderText, "Additional arg1", "Additional arg2");
        };

        $scope.controllerDemo = function () {
            //do some work

            //call the ctrl.setPlaceHolderText added by child
            if (ctrl.setPlaceHolderText) {
                ctrl.setPlaceHolderText();
            }
        };
    };
    return directive;
})

.directive("childDirective", function () {
    var directive = {};
    directive.restrict = "E";
    directive.scope = {};
    directive.require = ["^parentDirective", "?ngModel"];
    directive.template = '<div></div>';
    directive.link = function (scope, elem, attrs, ctrl) {
        var parentDirCtrl = ctrl[0];
        //allow parent scope(s) to $broadcast event
        scope.$on(parentDirCtrl.events.setPlaceHolderText,
            function (event, arg1, arg2) {
                elem.html("$Broadcast: " + arg1 + " " + arg2);
            });

        //Add function to parent controller
        parentDirCtrl.setPlaceHolderText = function () {
            elem.html("Added to parent controller!");
        }
    };

    return directive;
});

If you have multiple childDirectives and you go with adding function to parent directive controller, you will have to take precaution because each additional child directive would clobber the ctrl.setPlaceHolderText (i.e. only one elem.html would be called).

The bindonce library uses something similar to the second technique to allow child directives to add "binders" to the parent directive. The eventing model is probably cleaner for your purposes, but wanted to provide another option for directive communication.

Comments

0

Broadcast is not preferred, since If there is multiple instance of child or even parent child combination then broadcast will trigger all.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.