I'm trying to use ngRepeat in a directive - but I really don't know how to do it. Am I close?
Mowers is an array in my controller where this directive is used.
.directive('slider', function() {
return function() {
template: '<slider><film><frame ng-repeat="mower in mowers">{{mower.series}}</frame></film></slider>';
replace: true;
scope: true;
link: function postLink(scope, iElement, iAttrs) {
// jquery to animate
}
}
});
Yes, you're close, but the syntax was off. and you need to assign something to mowers on your scope.
.directive('slider', function() {
return {
restrict: 'E', //to an element.
template: '<film><frame ng-repeat="mower in mowers">{{mower.series}}</frame></film>',
replace: true,
scope: true, // creates a new child scope that prototypically inherits
link: function postLink(scope, iElement, iAttrs) {
scope.mowers = [
{ series: 1 },
{ series: 2 },
{ series: 3 }
];
}
}
});
Also, you need to not reference <slider> in itself.
The above code also assumes you've made directives for <film> and <frame>.
Finally, if you wanted to pass the mowers array in from an external scope, you'd change your scope setting to this:
scope: {
mowers: '='
}
And you could then set it like so:
<slider mowers="myMowers"></slider>
where myMowers is a variable on your controller or parent directive's scope.
I hope that helps.
Related
I have a Directive:
var ActorDisplayDirective = function() {
return {
replace : false,
restrict : 'AE',
scope : {
actor : "="
},
templateUrl: staticContext + '/angular-app/templates/actor-display-template.html',
link : function(scope, elem, attrs) {
},
}
};
This works fine in some places, but not others. Here is my code to show it where it is not working:
<p>CAP: {{can_approve_for}}</p>
<p>
Actor display template:
<span actor-display actor='can_approve_for'></span>
After template
</p>
The CAP: ... displays the data, the directive's actor value is null. Why? My controller does:
dataFactory.getCanApproveFor().then(function(data) {
$scope.can_approve_for = data;
});
So, I am able to see the value on the page, but the directive does not show it. I'm assuming it's a timing/refresh thing, but this directive works elsewhere in ng-repeat, because the ng-repeat evaluates after hte object is already set, I guess. How do I do it in this case?
You are not actually declaring ActorDisplayDirective as a directive. Its just a plain function that returns an object that sort of looks like a directive.
You have to tell angular that it is a directive like so:
angular.module('someModule', [])
.directive('actorDisplay', function () {
return {
replace: false,
restrict: 'AE',
scope: {
actor: "="
},
templateUrl: staticContext + '/angular-app/templates/actor-display-template.html',
link: function (scope, elem, attrs) {
},
}
})
I'm relative new to AngularJS and trying to create a directive for add some buttons. I'm trying to modify the controller scope from inside the directive but I can't get it to work. Here is an example of my app
app.controller('invoiceManagementController', ['$scope', function ($scope) {
$scope.gridViewOptions = {
isFilterShown: false,
isCompact: false
};
}]);
app.directive('buttons', function () {
return {
restrict: 'A',
template: '<button type="button" data-button="search" title="Filter"><i class="glyphicon glyphicon-search"></i></button>',
scope: {
gridViewOptions: '='
},
transclude: true,
link: function (scope, element, attr, ctrl, transclude) {
element.find("button[data-button='search']").bind('click', function (evt) {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown
transclude(scope.$parent, function (clone, scope) {
element.append(clone);
});
});
}
};
});
My HTML like following
{{ gridViewOptions.isFilterShown }}
<div data-buttons="buttons" data-grid-view-options="gridViewOptions"></div>
The scope inside the directive does change but is like isolated, I did try paying with the scope property and transclude but I'm probably missing something, would appreciate some light here
When you modify scope inside of your directive's link function, you are modifying your directive's isolated scope (because that is what you have set up). To modify the parent scope, you can put the scope assignment inside of your transclude function:
transclude(scope.$parent, function (clone, scope) {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown
element.append(clone);
});
Ok finally found a solution for this after some more research today. Not sure if the best solution, but this works so good for now.
app.controller('invoiceManagementController', ['$scope', function ($scope) {
$scope.gridViewOptions = {
isFilterShown: false,
isCompact: false
};
}]);
app.directive('buttons', function () {
return {
restrict: 'A',
template: '<button type="button" data-button="search" data-ng-class="gridViewOptions.isFilterShown ? \'active\' : ''" title="Filter"><i class="glyphicon glyphicon-search"></i></button>',
scope: {
gridViewOptions: '='
},
link: function (scope, element, attr, ctrl, transclude) {
element.find("button[data-button='search']").bind('click', function (evt) {
scope.$apply(function () {
// Set the property to the opposite value
scope.gridViewOptions.isFilterShown = !scope.gridViewOptions.isFilterShown;
});
});
}
};
});
I want to nest two directives and the inner directive has a ng-class bound to a function that takes a scope attribute from inner and outer scopes and return a Boolean
This is the HTML:
<ul my-toolbar disabled-when="myCtrl.isProcessing" >
<li my-action-button action="myCtrl.action()" disable-when="myCtrl.isSad()" />
</ul>
This is my outer directive:
myApp.directive("myToolbar", function() {
return {
restrict: 'A',
scope: {
disabled: '=disabledWhen'
},
transclude: true,
controller: function($scope) {
this.isDisabled = function() {
return $scope.disabled;
}
}
};
});
And this is my inner directive:
myApp.directive("myActionButton", function() {
return {
restrict: 'A',
scope: {
action: '&',
disabled: '=disabledWhen'
},
replace: true,
template: "<li ng-class='{disabled: isDisabled()}'><a ng-click='isDisabled() || action()' /></li>",
link: function(scope, elem, attrs, toolbarCtrl) {
scope.isDisabled = function() {
return toolbarCtrl.isDisabled() || scope.disabled;
};
}
};
});
Now the problem is that the ng-class='{disabled: isDisabled()}' binding is initialized once in the beginning but not updated when myCtrl.isProcessing changes!
Can someone please explain why? and how can I fix this without changing my design?
#Jonathan as requested I put my angular code in a fiddle and (this is part that's irritating me now) it works!
http://jsfiddle.net/shantanusinghal/ST3kH/1/
Now, I'll go back to seeing why it doesn't work for me in my production code!! *puzzled
I have a list of person objects. I have a directive for displaying some read only data about the person and nested inside it a directive that acts as the toolbar for actions on the person (delete, friend etc). When you click on the first directive a second nested directive shows up to for editing the person.
In the simple example in plnker this works fine, but in actual life this gets really flimsy with fields not updating, or updating infinitely (editor has quite a few ngRepeats making things even weirder) etc.
It seems awkward that I have 3 isolated scopes and pass the the same object to all three, but on the other hand I need a lot of properties/methods of that object in all 3 directives so it makes sense to pass the whole object. Is there a better way of doing this?
app.directive('personCard', [function () {
var directive = {
link: link,
restrict: 'A',
templateUrl: 'personcard.tpl.html',
scope: {
person: '='
}
};
return directive;
function link(scope, element, attrs) {
scope.isOpen = false;
scope.person.close = function(){
scope.isOpen = false;
}
scope.person.edit = function (){
scope.isOpen = true;
}
}
}]);
app.directive('personToolbar', [
function () {
var directive = {
link: link,
restrict: 'A',
templateUrl: 'personcardtoolbar.tpl.html',
scope: {
person: '=',
close: '&',
edit: '&'
}
};
return directive;
function link(scope, element, attrs) {
}
}]);
app.directive('personEditor', [
function () {
var directive = {
link: link,
restrict: 'A',
templateUrl: 'personeditor.tpl.html',
scope: {
person: '='
}
};
return directive;
function link(scope, element, attrs) {
}
}]);
I'm trying to set variable in isolate scope, but I can't access variable that I set in linked function in isolate scope and also I can access controller's variable.
app.directive('myDir', function($timeout) {
return {
restrict: 'A',
scope: {
'propVar': '='
},
link: function(scope, elem) {
console.log(elem)
scope.linkVar = 'It works!'
console.log(scope);
},
}
})
I created plunker to show what I mean: http://plnkr.co/edit/lUBvIkF4fKXkEgujJpuU?p=preview
It work's all as it should be.
1) If you define 'propVar' : '=' it means that your directive element has an attribute prop-var. This is not the case. If you would like to use the prop attribute you have to define your isolated scope in this way: 'propVar' : '=prop'.
2) The child elements of your directive are bound to the controllers scope not to the directive scope. If you would like the the child elements to be part of your directive you may use a template in your directive:
app.directive('myDir', function() {
return {
restrict: 'A',
template: '<div><p>linkVar: {{ linkVar }}</p><p>propVar: {{ propVar }}</p><p>foo: {{ foo }}</p><button ng-click="foo=\'directive sucks\'">press me</button></div>',
scope: {
propVar: '=prop'
},
link: function(scope, elem) {
console.log(elem)
scope.linkVar = 'It works!'
console.log(scope);
},
}
})
see the modified PLUNKR: http://plnkr.co/edit/MHXXkmPdtfAUqtre4Fbg?p=preview