Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling child directive function from parent directive in AngularJs

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.

like image 930
jsbisht Avatar asked Dec 18 '14 19:12

jsbisht


2 Answers

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);
    });
}
like image 75
Reactgular Avatar answered Oct 15 '22 19:10

Reactgular


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.

like image 2
Patrick Avatar answered Oct 15 '22 19:10

Patrick