Tallan's Blog

Tallan’s Experts Share Their Knowledge on Technology, Trends and Solutions to Business Challenges

‘Calling Forward’ into AngularJS Directives

Bryan Cort

This post is based on a StackOverflow answer by Oliver Wienand that I came across while researching the AngularJS pattern described below.

Data binding between controller and directive in AngularJS can be a tricky subject for the uninitiated (and often, even for the initiated). AngularJS is great at providing the magic that makes data flow easily between components on the front end – except when it’s not. This post is an examination of one of the cases where not everything is straightforward.

The Problem:

Passing a callback function into a directive with isolate scope is simple – just a matter of creating the binding in the scope definition (callback: ‘&’). However, there is no built-in equivalent for exposing a directive function to the parent directive or controller. That is, if we have the (truncated) directive definition below, we’re going to have to do some work before calling “foo” from the parent directive or controller.

function dir() {
    return {
        restrict: 'E',
        templateUrl: '../App/Modules/Path/To/OurTemplate.html',
        scope: {
            data: '=',
        },
        link: link
    };


    function link(scope) {
        //our link function
    }


    function foo(scope) {
        //some code for fooing
    }
}
Option 1: Events

Typically, communication between controllers and directives that do not share scope is handled with events. A $rootscope.$broadcast() from the parent with a corresponding scope.$on() listener in our directive would certainly get the job done and is a viable option (especially in the case where we need to carry out other, related operations in other directives at the same time). However, event firing/catching has a lot of performance overhead and isn’t the best option when we need to make an isolated call to a function defined in a child directive.

Option 2: Directive control objects

The alternative to firing and listening for events is to bind a control object in your directive. The control object is defined as a typical 2-way binding and passed in from the parent as usual. The first step is to define the control object in the parent (a controller, in this example):

//parent controller code (if the parent is a directive, var vm = this; is unnecessary'
var vm = this;
//
vm.directiveControls = {
    ourDirective: {},
};

 

Then, we pass it to the directive:

<our-directive data="vm.ourData"
               control="vm.directiveControls.ourDirective">
</our-directive>

 

To which we have added a 2-way binding for the control object:

function dir() {
    return {
        restrict: 'E',
        templateUrl: '../App/Modules/Path/To/OurTemplate.html',
        scope: {
            data: '=',
            //now in addition to the directive's data, we bind a control
            control: '='
        },
        link: link
    };


    function link(scope) {
        //and in the link, we attach to that control any functionality we want to expose to the parent
        scope.internalControl = scope.control || {};
        scope.internalControl.foo = function () { foo(scope) };
    }


    function foo(scope) {
        //code for fooing
    }
}

 

And finally, we can call foo() from the controller:

//this now successfully calls foo() in the directive
vm.directiveControls.ourDirective.foo();

 

AngularJS puts a huge amount at our disposal as developers, and it can sometimes be daunting to pick the right tool for the job. I hope that this post has added to your toolbox and helped organize it (and your code) a bit better as well.


If you are interested in getting additional help with your web apps check out our Web Solutions Page or Contact Us today!

No comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

\\\