Transclude not injected in link function - javascript

Here is my code
'use strict';
angular.module('app')
.directive('item'
, ["$timeout"
, "$Service"
, function(
$timeout
, $utils) {
return {
restrict: 'A',
scope: {
item: '=',
},
transclude: true,
link: function(scope, element, attrs, ctrl, transclude){
},
templateUrl: $fsUtils.getRelativeUrl('templates/item.html'),
controller: 'ItemCtrl',
};
}]);
My index.html:
<item><div>Transcluded content.</div></item>
transclude variable is undefined and ctrl variable is proto__: Object.
I need to inject parent scope into transcluded scope. The transclude variable is undefined. Where am I going wrong.
My angular version is 1.1.5
Thanks.

What you're looking for is the transcludeFn. Try this:
transclude: true,
transcludeFn: function () { /*do your stuff here*/ },
...
link: function(scope, element, attrs, controller, transcludeFn)
To access controller in link function you can do this:
var controller = scope.controller;

Related

Displaying constants within directive view after successfully injecting

question regarding constants within angularjs. I have the following constants created within app.js:
... angular
.module('blocTime', ['firebase', 'ui.router'])
.config(config)
.constant('STOP_WATCH', {
"workTime": 1500,
"breakTime": 300
});
})();
I've injected the constant inside my directive as follows:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
console.log(STOP_WATCH.workTime); ...
...
angular
.module('blocTime')
.directive('clockTimer', clockTimer);
I can console log the constant from my directive just fine. However, my view is not rendering the constant. HTML:
<div>
<div class="stop-watch">{{ STOP_WATCH.workTime }}</div>
It comes back as undefined. Thoughts as to why or how to make it display in the view? Thanks
Figured it out. Within my directive I had to add scope.STOP_WATCH = STOP_WATCH:
(function() {
function clockTimer($interval, $window, STOP_WATCH) {
return {
templateUrl: '/templates/directives/clock_timer.html',
replace: true,
restrict: 'E',
scope: {},
link: function(scope, element, attributes) {
scope.STOP_WATCH = STOP_WATCH;
...

Angular: get attribute from directive

I have no idea why, but:
#myApp.directive 'myDirective', () ->
return {
restrict: 'E',
scope: {
source: '='
},
link: (scope, element, attrs) ->
console.log scope.source
}
<my-directive source="foobar"></my-directive>
returns undefined. The thing which confuses me is that in my other directive, print-user, everything works fine.
return {
restrict: 'E',
scope: {
user: '=',
showName: '=',
showAvatar: '=',
avatarSize: '='
},
templateUrl: 'templates/partials/print-user.html',
link: (scope, element, attrs) ->
scope.tooltip = scope.user.username
}
Here I'm able to get the user object within the template by {{user}}.
Within myDirective I could get the source attribute by attrs.source - but why is it working within my user directive?
EDIT / Solution
Thanks to Aleksandar Bencun: using <my-directive source="'foobar'"></my-directive> (additional single quotes) solved the problem.

How can I access the controller instance associated with a directive from the link function?

How can I access the controller instance associated with a directive from the link function?
return {
template: template,
controller: controller,
controllerAs: 'myCtrl', // How do I access the controller instance from the link function?
restrict: 'E',
replace: true,
link: function(scope, element, attrs) {}
};
The link function in directive accepts 4th parameter. You can do the following:
return {
template: template,
controller: controller,
controllerAs: 'myCtrl',
restrict: 'E',
replace: true,
link: function(scope, element, attrs, controller) {}
};

Interaction of directive and controller in AngularJS

I want to create a component that displays itself as a collapsible box.
When it is expanded, it should show the transcluded content; when it is collapsed it should only show its label.
myApp.directive('collapsingBox', function() {
return {
restrict: 'E',
transclude: true,
require: '^ngModel',
scope: {
ngModel: '='
},
template: '<div ng-controller="CollapseController" class="collapsingBox"><div class="label">Title: {{ ngModel.title }}</div><br/><div ng-transclude ng-show="expanded">Test</div></div>',
link: function($scope, element, attr) {
element.bind('click', function() {
alert('Clicked!');
$scope.toggle();
});
}
};
});
This component should be reusable and nestable, so I wanted to manage the values (like "title" and "expanded") in a controller that gets instantiated for every use of the directive:
myApp.controller('CollapseController', ['$scope', function($scope) {
$scope.expanded = true;
$scope.toggle = function() {
$scope.expanded = !$scope.expanded;
};
}]);
This "almost" seems to work:
http://plnkr.co/edit/pyYV0MAikXThvMO8BF69
The only thing that does not work seems to be accessing the controller's scope from the event handler bound during linking.
link: function($scope, element, attr) {
element.bind('click', function() {
alert('Clicked!');
$scope.toggle(); // this is an error -- toggle is not found in scope
});
}
Is this the correct (usual?) way to create one instance of the controller per use of the directive?
How can I access the toggle-Function from the handler?
Rather than using ng-controller on your directive's template, you need to put the controller in your directive's controller property:
return {
restrict: 'E',
transclude: true,
require: '^ngModel',
scope: {
ngModel: '='
},
template: '<div class="collapsingBox"><div class="label">Title: {{ ngModel.title }}</div><br/><div ng-transclude ng-show="expanded">Test</div></div>',
controller: 'CollapseController',
link: function($scope, element, attr) {
element.bind('click', function() {
alert('Clicked!');
$scope.toggle();
});
}
};
As it is CollapseController's scope will be a child scope of your directive's scope, which is why toggle() isn't showing up there.

Angular is not able to find required controller in directive

I am trying to create series of directives which cummunicates via controller. This is what I have now:
angular.module('drmApp')
.directive('formInput', function () {
return {
templateUrl: 'views/directives/forminput.html',
restrict: 'E',
controller: 'ForminputCtrl',
controllerAs: 'ctrl',
bindToController: true,
transclude: true,
scope: {
model: '=',
errors: '=',
property: '#',
label: '#',
form: '=?',
},
link: function postLink(scope, element, attrs, ctrl, $transcludeFn) {
console.log($transcludeFn());
}
};
})
.directive('formInputValidationSummary', function() {
return {
restrict: 'E',
require: '^formInput',
transclude: true,
link: function postLink(scope, element, attrs, ctrl, $transcludeFn) {
ctrl.setValidationSummary($transcludeFn);
}
}
})
.directive('formInputContent', function() {
return {
restrict: 'E',
require: '^formInput',
transclude: true,
link: function postLink(scope, element, attrs, ctrl, $transcludeFn) {
ctrl.setInput($transcludeFn);
}
}
});
HTML Markup:
<form-input model="entity"
label="{{ 'WYKONAWCA_COLOR' | translate }}"
errors="errors"
property="color"
form="form">
<form-input-content>
<input colorpicker="rgb" ng-model="model.color" type="text">
</form-input-content>
</form-input>
Sadly, currently I am receiving this error:
Error: [$compile:ctreq] Controller 'formInput', required by directive 'formInputContent', can't be found!
I am using latest angular from v1.4 series. Also, this does not work with angular ~1.3. Is there something that I have forgot about? Did I misunderstand directive features?
Since you are transcluding transclude: true, Angular yanks the transcluded content out of the DOM - so, <form-input-content> is now not a child of <form-input>.
Then, when you are invoking the transclude function, this links the directive - and at that time it complains about not being able to find the parent formInput controller.
When you transclude, be sure to place the transcluded content back in the DOM:
link: function postLink(scope, element, attrs, ctrl, $transcludeFn) {
$transcludeFn(function(transcludedContentClone){
// this happens prior to linking of transcluded content
element.append(transcludedContentClone);
});
// ...
}

Categories

Resources