I am trying to access the attributes of a directive in the controller function. However, by the time I access it, it is undefined. I noticed that if I do a simple timer it works. Is there a way to execute code only after the directive and it's scopes are ready and set to be used?
I made a fiddle with it. Make sure your console is open. http://jsfiddle.net/paulocoelho/uKA2L/1/
Here is the code I am using in the fiddle:
<div ng-app="testApp" > <testcomponent text="hello!"></testcomponent> </div>
var module = angular.module('testApp', []) .directive('testcomponent', function () { return { restrict: 'E', template: '<div><p>{{text}} This will run fine! </p></div>', scope: { text: '@text' }, controller: function ($scope, $element) { console.log($scope.text); // this will return undefined setTimeout(function () { console.log($scope.text); // this will return the actual value... }, 1000); }, link: function ($scope, $element, $attrs) { console.log($scope.text); setTimeout(function () { console.log($scope.text); }, 1000); } }; });
You just create a myVar variable in your controller and pass it to the directive using my-var attribute. Since you are using two way binding, any changes made to myVar by the directive are available in your controller.
The ng-controller directive adds a controller to your application. In the controller you can write code, and make functions and variables, which will be parts of an object, available inside the current HTML element. In AngularJS this object is called a scope.
A controller is usually used to contain and maintain the logic for your view, which gets bound to your view via $scope. A directive is something that you might use repeatedly and is called in your view directly through the directive name which you can pass in as an attribute.
The ngRef attribute tells AngularJS to assign the controller of a component (or a directive) to the given property in the current scope. It is also possible to add the jqlite-wrapped DOM element to the scope. The ngRepeat directive instantiates a template once per item from a collection.
What works is, if you set
scope.text = $attrs.text;
inside the linking and the controller functions. This will only work initially, as there is no 2way- databinding. You can use $attrs.observe though.
See fiddle: http://jsfiddle.net/JohannesJo/nm3FL/2/
In an isolated scope, a local scope property defined with '@' can not be accessed in the linking function. As @remigio already mentioned, such local scope properties are undefined
at that point. $attrs.$observe() or $scope.$watch() must be used to asynchronously obtain the (interpolated) value.
If you are passing a constant value in the attribute, (i.e., no interpolation required, i.e., the attribute's value doesn't contain any {{}}s) there is no need for '@' or $observer or $watch. You can use $attrs.attribute_name once as @hugo suggests, or if you are passing a number or a boolean and you want to get the proper type, you can use $scope.$eval($attrs.attribute_name) once.
If you use '=' to databind a local scope property to a parent scope property, the value of the property will be available in the linking function (no need for $observe or $watch or $eval).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With