angular directive attributes isolate scope undefined outside ng-repeat - angularjs

I have directive this directive:
myApp.directive('myDirective',['$http', function($http) {
return {
restrict: 'AEC',
replace: true,
scope: { attr1: '=' , attr2: '=' },
link: function(scope, element, attrs) {
...
}
}]);
If I put directive inner ng-repeat it works, so I have acces to value of attributes (eg. scope.attr1)
<div ng-repeat="item in items"
<my-directive attr1="item.value1" attr2="item.value2"></my-directive>
</div>
but if I put directive outside ng-repeat, so I have only my-directive:
{{mymodel.value1}} {{mymodel.value2}} //{{}} print correct value
<my-directive attr1="mymodel.value1" attr2="mymodel.value2"></my-directive> //this fail
I can't access to attributes, so If I access eg. scope.attr1 I'm getting undefined value.

the "item" object is only defined in the div with the ngRepeat so when you are trying to access specific items from the list "items" outside of the div with ngRepeat you have to use items[index].value1 syntax. Try:
<my-directive attr1="items[index].value1" attr2="items[index].value2"></my-directive>

If the values are simple types, you should use '#' instead of the two-way model binding that '=' implies.
Also how are you reading your values. Do you read them through scope.attr1 or attrs['attr1'] - since the attr collection only holds the value in the attributes, whereas the scope actually lnks to the objects

There should be nothing wrong with your code. Maybe you could spot what you're doing differently:
Working Example Here

Related

Angular: data not passing from controller to directive using isloated scope

The question title explain my problem i want to send data from a controller to directive so i can use the data in the directive controller or view.
Here is the controller code:
$scope.following = product.vendorId.isUserFollowing;
In the controller view:
<vas-follow following="{{following}}"></vas-follow>
following the property am trying to pass to the directive, the directive code:
.directive('vasFollow', vasFollow);
function vasFollow() {
var directive = {
restrict: "EA",
scope: {
following: '#'
},
link: link,
controller: vasFollowCtrl,
templateUrl: 'templates/directives/vasFollow.html',
};
return directive;
function link(scope, element, attrs) {
/* */
};
}
I tried first to use the following like so {{following}} in the directive view but it's not passing, also it is undefined in the directive controller.
I have read a lot of slimier issues but, i couldn't conclude why am having this problem.
Use ng-model for directive instead of your own replacement for it
Remove {{}} from assignment to share link to variable instead of just evaluated value
And please, use div or common DOM element instead of exact naming directive - it have side-effects in I.E.

Accessing parent scope from isolated scope

I'm trying to write attribute directive that wraps element and decorates it with some other things along with additional directives. And I need to keep content inside the element intact. Something like this:
app.controller 'myCtrl', ($scope)->
$scope.name = "Gwendolyn"
app.directive 'niceName',($compile)->
restrict: 'A'
replace: yes
scope: niceName:"="
template: (element, attrs)->
"<div>
<div style='background:lightgray'>
#{element.html()}
</div>
<div>
<h1>{{nice}}</h1>
</div>
</div>"
controller: ($scope, $element)->
$scope.$watch 'hover',->
$scope.nice = if $scope.hover then $scope.niceName else ''
compile:(element, attrs)->
element.attr('ng-mouseover',"hover = true")
element.attr('ng-mouseout',"hover = false")
element.removeAttr('nice-name') # removing itself to avoid from falling into infinite loop
pre:(scope, iElement, iAttrs)->
$compile(iElement)(scope)
Markup:
<div nice-name="uglyname">
<h2>{{uglyname}}</h2>
<div>
Now that thing doesn't work at all, it won't render h2 part because now uglyname is unknown to the current scope. I can compile it with passing the parent scope, but then it totally breaks my controller. (see jsbin below)
So somehow I have to compile content of the element applying parent scope, add it to the template and then compile again applying local scope? Or I need to find a way to inherit properties of parent scope? Or I can't do it with attribute directive? Maybe I need to use element directive and transclusion?
Any ideas?
jsbin
i would do what #marfarma suggested as well as change you html to not include the brackets so:
scope: { niceName: "="},
and
nice-name="uglyname"

Custom directive in ng-repeat with isolated scope : loop items are suddenly null

I'm trying to use a custom directive in an ng-repeat loop. Without my custom directive the loop works fine: all items are displayed. But if I use my directive on the ng-repeat then all the items in the loop seem to be undefined or null, at least not printed.
Here is a simplified example:
http://jsfiddle.net/vtH64/13/
angular.module('myTest', []).directive('makecool', function(){
return {
scope: {
'flippity': '&'
},
link: function(scope, element){
element.append(", Yo!");
// do something with flippity
}
};
});
angular.module('myApp',['myTest']).controller('ListStuff', function($scope){
$scope.list = ["hi","there","this","be","a","list"];
});
It seems to have something to do with the isolated scope, because without the
scope: {
'flippity': '&'
},
which isolates the scope it works fine (http://jsfiddle.net/vtH64/15/), eventhough I will not be able to access 'flippity', which I need in the real world app.
What I am doing wrong here?
link method gets element's attributes as the third argument:
link: function(scope, element , attributes){
So you can get the flippity in a very easy way: attrs["flippity"]
Working fiddle: http://jsfiddle.net/vtH64/17/
Try with $parent if you are including the isolated scope...
<li ng-repeat="item in list" flippity="flop" makeCool>{{$parent.item}}</li>

Access repeated item inside ng-repeated directive

I'm building a custom directive in AngularJS that I need to be repeated a couple of times. Currently, my page looks like this:
<div my-item ng-repeat="item in items" />
And my directive looks like this:
module.directive('myItem', function() {
return {
restrict: 'A',
replace: true,
scope: { item: '&' },
template: '<div id="item{{$index}}"></div>',
link: function($scope, element, attributes) {
element.append('<div>' + $scope.item.name + '</div>');
}
};
});
However, inside the linking function, $scope.item.name yields undefined. I'm wondering if there is any way I could access the repeated item inside my directive.
If not, what would be my alternatives? Move the ng-repeat inside the directive, maybe?
P.S. I know that you should (generally speaking) not do DOM manipulation this way, but since I might have ~2000 items that would result in 6000 bindings, and I'm afraid that would lead to severe performance issues.
You should pass item as attribute to directive created a sample directive
http://plnkr.co/edit/l5r6zIc7ncT1XldRuB98?p=preview

Isolate scope attributes defined with # are undefined/disappear in directive's link function

The directive has isolate scope, and the scope attributes are being passed with "#".
This is how the directive is called:
<div ng-init="classForIcon = 'vladClass'"></div>
<div ng-init="textForIcon = 'Icon\'s text'"></div>
<div ng-init="routeForIcon = 'www.google.com'"></div>
<div ng-init="tooltipForIcon = 'my tooltip'"></div>
<div ng-init="imageForIcon = 'images/HOME_ICON1.png'"></div>
<rl-icon-widget icon-class="{{classForIcon}}" icon-text = "{{textForIcon}}" icon-tooltip="{{tooltipForIcon}}" icon-route="{{routeForIcon}}" icon-image="{{imageForIcon}}"></rl-icon-widget>
This is how the directive is defined:
'use strict';
fcPortalApp.directive('rlIconWidget', ['localizationAssistant', function(localizationAssistant) {
var obj = {
restrict: 'E',
templateUrl: 'scripts/directives/rliconwidget/rliconwidget.html',
//require: 'ngModel',
scope: {
//ngModel: '#',
iconClass: "#",
iconRoute: "#",
iconText: "#",
iconTooltip: "#",
iconImage: "#"
},
link: function(scope, element, attrs) {
console.log(scope);
console.log(scope.iconImage);
console.log(scope.iconTooltip);
console.log(scope.iconRoute);
}
};
console.log(obj);
return obj;
}]);
When I inspect the scope object (click on the output of console.log(scope_ in firebug), it looks like it has iconImage, iconTooltip and iconRoute properties set correctly.
Yet console.log(scope.iconImage), console.log(scope.iconTooltip) and console.log(scope.iconRoute) print "undefined"
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. -- directive doc
By the time you manually inspect the scope, the values get defined.
The reason we need to use $observe (actually $watch will also work for isolate scope properties defined with '#') is because a directive will likely need to do something whenever the interpolated value changes. E.g., if the value of textForIcon changes, you may want to modify something in the DOM that is managed by your directive.
If you need the values defined when the linking function runs, you have two options:
Use '=' instead of '#'. This will require that you remove the {{}}s from the HTML.
If the values won't change, pass strings: <rl-icon-widget icon-class="vladClass" ...> Then in your directive, simply use attrs.iconClass -- no need for '#'.

Resources