Abdul23
Abdul23

Reputation: 6015

angularjs directive: how communicate between link and controller?

I have a directive whose 'config' attribute value I need to access inside my directive controller. Since the controller constructor get executed first,communication from controller to link is possible but not vice versa. What should be the best way to achieve this? I have considered the following approaches

1)Add the variable to scope- That would in my opinion pollute the scope,making the variable accessible every where else where the scope is being shared.

2)Use $broadcast Again the same issue as above

3) Pass a callback function on controller's this and call it from the link function with config as its argument

4)Pass the value through a service- In my case I have multiple such directives that would need to pass date through this service

Or is there some better approach that I am missing out for doing this?

module.directive('myDirective',function(){

return{
 restrict:'E',
 templateUrl:'path/to/html',
 link:function(scope,iElement,iAttrs,controller){

  var config=iAttrs.config;
//How to access this value inside the directive controller?

},
controller:function($scope){
//the directive attribute 'config' is required here for some larger computations which are not
//manipulating the DOM and hence should be seperated from the link function
})

Upvotes: 1

Views: 4817

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136144

There you can use isolated scope concept where you create isolated scope inside your controller & that would not be prototypically inherited from its parent scope. For that you need to use scope: { ... } inside your directive option. There are three options to pass scope value inside a directive through attribute

  1. @ : One way binding
  2. = : Two way binding
  3. & : Expression

In your case first two cases would be fine that are depends which one you need to use. If you just want to pass the value of scope variable to the directive in that case you could use 1st approach which would be @ one way binding.

If you want to update the variable in both directive as well as controller from where it come i.e. nothing but two way binding, then you need to use =

I think = suits in your case so you should go for =

Markup

<my-directive config="config"></my-directive>

Directive

app.directive('myDirective', function() {
  return {
    restrict: 'E',
    scope: {
      config: '='
    },
    templateUrl: 'path/to/abc.html',
    link: function(scope, iElement, iAttrs, controller) {
      //here it will be access as scope.config
      console.log(scope.config);
    },
    controller: function($scope) {
      console.log($scope.config); //here also it would be available inisde scope
      //you could put a watch to detect a changes on config
    }
  }
});

Demo Plunkr

Update

As config value has been provide from the attribute with expression like {{}} so we could get those changes inside controller by putting [**$observe**][2] on $attrs. For that you need to inject $attrs dependency on your controller that will give you all the attributes collection which are available on directive element. And on the same $attrs object we gonna put $observe which work same as that of $watch which does dirty checking & if value gets change it fires that watch.

Directive

app.directive('myDirective', function() {
  return {
    restrict: 'E',
    templateUrl: 'path/to/abc.html',
    link: function(scope, iElement, iAttrs, controller) {
      //here it will be access as scope.config
      console.log(scope.config);
    },
    controller: function($scope,$attrs) {
      //you could put a watch to detect a changes on config
      $attrs.$observe('config', function(newV){
        console.log(newV);
      })
    }
  }
});

Updated Demo

Upvotes: 3

Related Questions