How to Get Evaluated Attributes Inside a Custom Directive

How to get evaluated attributes inside a custom directive

Notice: I do update this answer as I find better solutions. I also keep the old answers for future reference as long as they remain related. Latest and best answer comes first.

Better answer:

Directives in angularjs are very powerful, but it takes time to comprehend which processes lie behind them.

While creating directives, angularjs allows you to create an isolated scope with some bindings to the parent scope. These bindings are specified by the attribute you attach the element in DOM and how you define scope property in the directive definition object.

There are 3 types of binding options which you can define in scope and you write those as prefixes related attribute.

angular.module("myApp", []).directive("myDirective", function () {
return {
restrict: "A",
scope: {
text: "@myText",
twoWayBind: "=myTwoWayBind",
oneWayBind: "&myOneWayBind"
}
};
}).controller("myController", function ($scope) {
$scope.foo = {name: "Umur"};
$scope.bar = "qwe";
});

HTML

<div ng-controller="myController">
<div my-directive my-text="hello {{ bar }}" my-two-way-bind="foo" my-one-way-bind="bar">
</div>
</div>

In that case, in the scope of directive (whether it's in linking function or controller), we can access these properties like this:

/* Directive scope */

in: $scope.text
out: "hello qwe"
// this would automatically update the changes of value in digest
// this is always string as dom attributes values are always strings

in: $scope.twoWayBind
out: {name:"Umur"}
// this would automatically update the changes of value in digest
// changes in this will be reflected in parent scope

// in directive's scope
in: $scope.twoWayBind.name = "John"

//in parent scope
in: $scope.foo.name
out: "John"

in: $scope.oneWayBind() // notice the function call, this binding is read only
out: "qwe"
// any changes here will not reflect in parent, as this only a getter .

"Still OK" Answer:

Since this answer got accepted, but has some issues, I'm going to update it to a better one. Apparently, $parse is a service which does not lie in properties of the current scope, which means it only takes angular expressions and cannot reach scope.
{{,}} expressions are compiled while angularjs initiating which means when we try to access them in our directives postlink method, they are already compiled. ({{1+1}} is 2 in directive already).

This is how you would want to use:

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

myApp.directive('myDirective', function ($parse) {
return function (scope, element, attr) {
element.val("value=" + $parse(attr.myDirective)(scope));
};
});

function MyCtrl($scope) {
$scope.aaa = 3432;
}​

.

<div ng-controller="MyCtrl">
<input my-directive="123">
<input my-directive="1+1">
<input my-directive="'1+1'">
<input my-directive="aaa">
</div>​​​​​​​​

One thing you should notice here is that, if you want set the value string, you should wrap it in quotes. (See 3rd input)

Here is the fiddle to play with: http://jsfiddle.net/neuTA/6/

Old Answer:

I'm not removing this for folks who can be misled like me, note that using $eval is perfectly fine the correct way to do it, but $parse has a different behavior, you probably won't need this to use in most of the cases.

The way to do it is, once again, using scope.$eval. Not only it compiles the angular expression, it has also access to the current scope's properties.

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

myApp.directive('myDirective', function () {
return function (scope, element, attr) {
element.val("value = "+ scope.$eval(attr.value));
}
});

function MyCtrl($scope) {

}​

What you are missing was $eval.

http://docs.angularjs.org/api/ng.$rootScope.Scope#$eval

Executes the expression on the current scope returning the result. Any exceptions in the expression are propagated (uncaught). This is useful when evaluating angular expressions.

AngularJs directives - how to get attributes values from within directive

Use $observe:

Observing interpolated attributes: Use $observe to observe the value changes of attributes that contain interpolation (e.g. src="{{bar}}"). Not only is this very efficient but it's also the only way to easily get the actual value because during the linking phase the interpolation hasn't been evaluated yet and so the value is at this time set to undefined. -- directives doc

return function(scope, element, attrs) {
attrs.$observe('key', function(value) {
console.log('key=', value);
});
}

As @FMM mentioned in a comment, data is stripped by Angular when it normalizes the attribute name, hence the use of key above, rather than dataKey.

How to access elements attributes from custom directive while keeping access to parent scope?

For what you are trying to do, do not need a two way binding. You are trying to access the text assigned as attribute. You could just write your directive as:-

.directive('testDirective', function(){
return {
restrict:"E",
//scope:true, //apply if required
templateUrl:"directive.html",
link:function(scope, elm, attrs){
scope.testAttribute = attrs.testAttribute; //Get it from attributes
}
};
});

Demo

Now here scope property of directive settings is going to use the parent scope itself. But ideal scenarios you may want to use scope:true (Child scope of parent) or a 2 way binding wit isolated scope. But at this point, since not really sure what is your original goal, this is a solution based on what you have in your question.

So to summarize:-

I want to be able to access the parent scope of the directive I have created

Remove the isolated scope and just use parent's scope.

but I also want to be able to access the attributes that I have placed onto the element.

Use attrs argument of the link function (attrs.testAttribute). If you want to evaluate it as a bound value the do (scope.$eval(attrs.testAttribute))

How to evaluate attributes inside an angular directive

Just use a single template:

<span>{{lang}}</span>
<img ng-if="lang !== '--' && lang !== '??'" ng-src="img/{{lang}}.png" />

AngularJS custom attribute does not evaluate first time directive runs

As it turns out the controller and controllerAs properties were having an effect on this. I removed it, but then decided I would rather have the controller so instead I used isolate scope to evaluate the object instead of reading it from the attr property.

AngularJS: How to set an attribute to a custom directive

Go Angular :-)

You don't need the use of jQuery here. Angular is sufficient enough. You can change your code like this:

In your View:

<keybuddy model="myInputText"></keybuddy>

<button ng-click="showText()">Show Text</button>

In your View controller:

$scope.showText = function() {
console.log($scope.myInputText);
}

And update your directive to have scope like below (replace your `scope: true):

scope: {
inputText: '=model'
}

Read more on Isolating scope of a directive

angular directive attributes not evaluated

1) Complex attributes are not being passed as objects despite using '=' (see code below) in scope

That is because you are getting them as attrs.whenNormal which is a string (JSON). You instead just need to access it from scope, i.e scope.whenNormal. It would just be same as scope.$eval(attrs.whenNormal) or JSON.parse(attrs.whenNormal)//provided your JSON is valid.
But the 2 way binding here doesn't make much sense though.

2) the function that should evaluate to provide one-way binding is also being passed as string instead.

That is because when you use function binding they get evaluated as getter with bound values (you specified bound value as RestEditCtrl.restaurant.id). Inorder to access the value, provided the function ajaxState returns something, you need to do curState = scope.btnState(); instead of curState = attrs.btnState, basically evaluate the getter to get the value.

Plnkr



Related Topics



Leave a reply



Submit