Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - get parent directive's controller in child directive's controller (not link function)

I'm aware how I can get parent's directive controller in the child directive's link function.
However, I'd prefer to avoid using link function (and $scope all-together) and have all my code under the controller function of the directive.

angular.directive('parent', function(){
    return {
        templateUrl: '/parent.html',
        scope: true,
        bindToController: true,
        controllerAs: 'parentCtrl',
        controller: function(){
            this.coolFunction = function(){
                console.log('cool');
            }
        }
    }
});

angular.directive('child', function(){
    return {
        templateUrl: '/child.html',
        require: '^parent',
        scope: true,
        bindToController: true,
        controllerAs: 'childCtrl',
        controller: function() {
            // I want to run coolFunction here.
            // How do I do it?
        }
    }
});

Any help is appreciated!

like image 478
Dmitry Efimenko Avatar asked Oct 19 '15 16:10

Dmitry Efimenko


2 Answers

The proper pattern for that would be

app.directive('child', function(){
    return {
        templateUrl: '/child.html',
        require: ['child', '^parent'],
        scope: true,
        bindToController: true,
        controllerAs: 'childCtrl',
        controller: function() {
            this.coolFunction = function () {
                this._parent.coolFunction();
            }
        },
        link: function (scope, element, attrs, ctrls) {
            var childCtrl = ctrls[0];
            var parentCtrl = ctrls[1];
            childCtrl._parent = parentCtrl;
        }
    }
});

The bad thing is that _parent is being exposed to scope with controllerAs, but it will rarely be a problem.

Notice that you won't have access to parent controller from child until link glues them together. Which is fine as long as you use parent controller in child methods.

Controller provides methods and initial properties to view model (and it does it cleaner with controllerAs), link glues the stuff, that's how directives work.

Both $scope and link have their purposes in Angular 1.x and are indispensable even with latest community developments. Banishing them for no valid reason is overzealous and may lead to bad design solutions. The absence of 'link' and 'scope' words in code won't help to make the app easier to port to 2.x. Though learning Angular 2 now and developing proper habits for 1.x will.

like image 57
Estus Flask Avatar answered Nov 18 '22 08:11

Estus Flask


You could inject '$element' into the controller and access the parent controller like -

  controller: ($element) ->
    var parentCtrl = $element.parent().controller('parent');
    parentCtrl.coolFunction();
    //..........
    //..........

This may not be the most transparent way of accessing 'any' parent controller because it requires the specific name of the directive and it is jqlite and not pure Angular.

Found this thread useful - How to access parent directive's controller by requiring it recursively?

EDIT: Thanks to @Dmitry for figuring out that angular doesn't need '.parent' to get the controller. Updated code -

  controller: ($element) ->
    var parentCtrl = $element.controller('parent');
    parentCtrl.coolFunction();
    //..........
like image 33
FrailWords Avatar answered Nov 18 '22 10:11

FrailWords