Yair Nevet
Yair Nevet

Reputation: 13013

Can't access controller scope from directive

This is my app config:

angular.module('myApp', ['myApp.directives', 'myApp.controllers', 'myApp.services']);

This is my controller:

angular.module('myApp.controllers', [])
  .controller('MainCtrl', function ($scope) {
      $scope.name = 'world';
  });

This is my directive:

var directives = angular.module('myApp.directives', []);

directives.directive("hello", function () {
    return function (scope, elm, attrs) {
        elm.text("hello, " + scope[attrs.name]);
    };
});

and this is my html:

<div ng-controller="MainCtrl">
    <h1 hello></h1>
</div>

The is problem is that angular render the directive as:

hello, undefined

Instead of:

hello, world

What is wrong?

Upvotes: 11

Views: 14165

Answers (4)

Mahbub
Mahbub

Reputation: 3118

You can access using scope. Look http://jsfiddle.net/rPUM5/

directives.directive("hello", function () {
    return function (scope, elm, attrs) {
        elm.text("hello, " + scope.name);
    };
});​

Upvotes: 3

Siwei
Siwei

Reputation: 21577

I found another case:

if you are accessing a variable coming from a Ajax request body, then you have to WAIT until the variable is set.

e.g:

# in controller
$http.get('/preview').then( (response) ->
  $scope.tabs = response.data.tabs
  $scope.master_switch = '1'
  console.info 'after get response in controller'
)

# in directive
directive('masterSwitch', ->
  (scope, element, attrs) ->
    alert 'in directive!'   # will show before "after get response in controller"
    console.info scope.master_switch  # is undefined
    setTimeout( -> console.info(scope.master_switch), 50) # => 1

Upvotes: 1

vcardillo
vcardillo

Reputation: 1706

You can do something that, as of writing this, appears to be undocumented in Angular (see Mark Rajcok's comment here: http://docs.angularjs.org/api/ng.$rootScope.Scope).

From within your directive:

scope.$parent.name

If you do a console.log(scope) on the directive's scope (from within the directive), you'll see these properties.

All this said, I don't know whether or not this is "proper" Angular convention, due to the fact that this is both undocumented, and I haven't found any other better documentation on how to access the controller that a directive sits within.

Upvotes: 6

Liviu T.
Liviu T.

Reputation: 23664

You are accessing scope[attrs.name] but the directive doesn't provide a value for the attribute name

There are 2 options:

  1. Change the directive to elm.text("hello, " + scope['name']); This is not a preferred way as it hard codes to a scope property name

  2. Change the html to <h1 hello name="name"></h1>. This is better but I feel it uses a redundant attribute

I would suggest you change the directive to elm.text("hello, " + scope[attrs['hello']]);

Or even better elm.text("hello, " + scope.$eval(attrs['hello']));

this way you get the benefit of expressions as well(ex: <h1 hello="name|uppercase"></h1>) demo

This way the html would be <h1 hello="name"></h1>

Regarding the attrs parameter: it's nothing more than a map of strings taken from the attributes present on the dom element.

Upvotes: 7

Related Questions