2

I have an Angular app where I'm using ui-grid. I want to have a custom action on a cell of the grid that calls a method from my app. So basically, this means calling a method that's somewhere up in the parent hierarchy, from a directive.

This would be achieved by calling something like: $scope.$parent.$parent.$parent.$parent.foo(). But that doesn't seem too nice.

One option would be to create a recursive function that goes up the ancestry of the $scope. That's nicer, but still seems a bit weird.

Also... Is it good practice to try to achieve something like this?

1
  • 1
    Probably use event. Commented Sep 2, 2015 at 12:51

2 Answers 2

4

You're correct that $parent.$parent.$parent is definitely not a good practice.

If the method you're calling is another directive, you can require that directive in your child directive and then, the parentDirective's controller function will be injected as the fourth parameter to your link function:

In your DDO:

return {
    require : '^parentDirective',
    restrict : 'E',
    link : function (scope, elem, attrs, parentDirectiveController) {}
}

If what you're trying to call is on a factory/service, you can inject that factory/service into your directive, although this sometimes is a code smell, depending on what you're trying to inject.

Finally, another way to do it is to use event propagation. From your directive, you can use $scope.$emit to send information up to parent controllers:

From the directive:

$scope.$emit('directiveDidStuff', {
    data : 'blah'
});

In the parent controller:

$scope.$on('directiveDidStuff', function (evt, params) {
    this.data = params.data;  // equals blah
});
Sign up to request clarification or add additional context in comments.

1 Comment

The $emit method was exactly what I needed. Thanks!
1

You can achieve the same by using "&" through one of the scope variable in directive.Like this, you can bind your event to the controller method and from the method, you could do your desired things or if the original business logic which you wants to achieve on onClick of the grid is used across many modules than you can bisect it in service and make it reusable and call the service from the event method. Let me know if you do have any doubts with the approach.

Key Code of example:

Html

   <my-component attribute-foo="{{foo}}" binding-foo="foo" isolated-expression- foo="updateFoo(newFoo)" >

Directive

    var myModule = angular.module('myModule', [])
.directive('myComponent', function () {
    return {
        restrict:'E',
        scope:{
            /* NOTE: Normally I would set my attributes and bindings
            to be the same name but I wanted to delineate between 
            parent and isolated scope. */                
            isolatedAttributeFoo:'@attributeFoo',
            isolatedBindingFoo:'=bindingFoo',
            isolatedExpressionFoo:'&'
        }        
    };
})

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.