Angular is not able to find required controller in directive - javascript

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);
});
// ...
}

Related

How to call a directive in angular js?

.directive('clinicalTrailModal', function ($compile) {
return {
restrict: 'EA',
scope: {
context: '=',
dui: '='
},
templateUrl: 'app/templates/lbdAdsModal.html'
})
I am calling this directive based on true false condition like below,
<clinical-trail-modal value="currentUrl" dui="typeDisease._id" data-ng-if="clinicalTrailModal"></clinical-trail-modal>
But it does'nt work.When I remove
restrict: 'EA',
scope: {
context: '=',
dui: '='
},
this it works.I am new to angularjs.Can anyone please help me.Thanks.
It's possibly failing due to you passing context into the scope. Either remove context, pass it in, or make it optional.
restrict: 'EA',
scope: {
context: '=?', //optional
dui: '='
}

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.

Transclude not injected in link function

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;

Categories

Resources