Directives, requires, angular js - angularjs

Got two directives. One is a "subdirective"
Main:
.directive('materialDropdown', function() {
// Input to directive
return {
scope: {
//'personalDb': '=',
},
transclude: true,
controllerAs: 'vm',
bindToController: true,
controller: function(){
console.log('material directive fires')
},
template: '<select></select>',
restrict: 'E',
link: function(){}
};
});
sub:
.directive('materialSizeDropdown', function() {
// Input to directive
return {
require: '^^materialDropdown',
controllerAs: 'vm',
transclude: true,
bindToController: true,
controller: function(){
console.log('hello')
},
template: '<h1>fire</h1>',
restrict: 'E',
link: function(){}
};
Markup:
<material-dropdown>
<material-size-dropdown></material-size-dropdown>
</material-dropdown>
The materialSizeDropdown is not shown in the markup, and the controller is not fired either.
How do I solve this?

You're using the template option on your materialDropdown directive which will use for rendering. So your nested directive will never shown. And a <h1> in a <select> would not be valid.

Related

Required controller cannot be found when using $transclude in required controller

Simplified example of the code....
HTML:
<div ng-app="app">
<m-carousel>
<m-carousel-slide>foo</m-carousel-slide>
<m-carousel-slide>bar</m-carousel-slide>
</m-carousel>
</div>
JavaScript:
class CarouselDirectiveController {
constructor($transclude) {
$transclude(clone => {
// do something
}, null, 'slide');
}
}
class CarouselSlideDirectiveController {
$onInit() {
console.log(this.carousel);
}
}
function carouselDirective() {
return {
restrict: 'E',
replace: true,
controller: CarouselDirectiveController,
controllerAs: 'carousel',
template: '<div class="m-carousel" ng-transclude="slide"></div>',
transclude: {
slide: 'mCarouselSlide'
},
scope: {},
bindToController: true
};
}
function carouselSlideDirective() {
return {
restrict: 'E',
replace: true,
transclude: true,
controller: CarouselSlideDirectiveController,
controllerAs: 'carouselSlide',
template: '<div class="m-carousel-slide" ng-transclude></div>',
scope: {},
bindToController: true,
require: {
carousel: '^^mCarousel'
}
};
}
angular.module('app.carousel', [])
.directive('mCarousel', carouselDirective)
.directive('mCarouselSlide', carouselSlideDirective);
angular.module('app', ['app.carousel']);
This throws the following error:
https://docs.angularjs.org/error/$compile/ctreq?p0=mCarousel&p1=mCarouselSlide
However, if I comment out the $transclude(clone => {}, null, 'slide'); then all is good in the world... How do I access the transcluded content in a parent controller if the controller is required by another?
CodePen: http://codepen.io/anon/pen/KzdNRE?editors=1011
I figured out what this was way back when... If you use $transclude this way you have to remember to manually append the transcluded content. So...
$transclude(clone => {
// do something then...
$element.append(clone);
}, null, 'slide');

Not able to render angular directive templateURL inside ng-init method

I am facing issue while rendering directive inside nginit method.
first directive :
Controller :
$scope.addDetails(asset) {
asset.label = "<div window></div>";
};
return {
restrict: "EA",
scope: true,
controller: "demoController",
controllerAs: "vms",
template:
"<div data-ng-repeat = 'data in vms.details' ng-init='vms.addDetails(data);'" +
</div>"
};
window directive:
return {
restrict:"AE",
templateURL: "infowindow.html"
};
With the below approach it worked with me we shouldn't do any complex logic(DOM rendering) when we use ng-repeat with ng-init. if so we need to construct the directive after the data is rendered.
$scope.details= {asset:1,description:"sample text"};
$scope.addLabel(asset) {
asset.label = "sample text to be shown in other directive";
};
return {
restrict: "EA",
bindToController: {details:'='}
scope: true,
controller: "demoController",
controllerAs: "vms",
template:
"<div data-ng-repeat = 'data in vms.details' ng-init='vms.addLabel(data);'" +
"<div window label-text=data.label></div>" +
</div>"
};
window directive:
return {
restrict:"AE",
bindToController:{labelText: '#'},
scope:true,
templateURL: "infowindow.html"
};
infowindow.html
<div>{{vms.labelText}}</div>

AngularJs Multiple Directive

I am working on multiple directive, this is already existing framework so I dont want to disturb the existing components.
This is my HTML
<div title="test" mydirective>
This is my directive, this has templateUrl with it and this template has another directive getting loaded.
.directive('myDirective', function ($filter) {
restrict: 'A',
replace: true,
transclude: true,
scope: {
title: '#'
},
templateUrl: 'partial/partialtemplate.tpl.html'
});
My Partial Template html looks like this
<div newdirective title="{{title}}"></div>
This is my newdirective
.directive('newDirective', function ($filter) {
restrict: 'A',
replace: true,
transclude: true,
scope: {
title: '#'
},
templateUrl: 'partial/newpartialtemplate.tpl.html',
controller: function ($scope, $attrs) {
//here if I try to print my title I still get {{title}}
console.log($attrs.title);
}
});
So what could the issue be, I the second directive being called even before the template data is written or anything wrong?

How can I pass a template to a directive in an attribute?

I want to pass a template to a directive like this:
<my-directive template="/templates/my-directive-template.html"></my-directive>
If no template is provided then the standard template is used.
How can I achieve this?
Or shouldn't I do this? I just want to reuse a directive, but want to give it different appearances each time.
Here's the directive... but I'm stuck on how to move forward.
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=template'
},
template: 'standard-template.html'
}
})
templateUrl can be a function, that gets the element and its attributes as arguments. So you can do the following:
app.directive('my-directive', function(){
return {
restrict: 'E',
templateUrl: function(element, attrs) {
return attrs.template || 'standard-template.html';
}
You could use ng-include. So as an example
app.directive('my-directive', function(){
return {
restrict: 'E',
scope: {
template: '=?'
},
template: '<div ng-include="directiveTemplate"></div>',
link: function (scope) {
scope.directiveTemplate = scope.template || '/path/to/default.tpl.html';
}
}
})

Accessing parent's parent controllers through Angular require attribute

In the below example, the accordion-group directive shares a controller and scope with the parent accordion, using the "require: '^accordion'" attribute within the accordion-group directive.
If I wanted to create a child directive, under accordion-group, how would it access the accordion controller as well? Requiring ^accordion and ^accordionGroup do not seem to work.
https://github.com/angular-ui/bootstrap/blob/master/src/accordion/accordion.js
It does work that way. I was just being stupid.
Fiddle for posterity here.
'use strict';
angular.module('myApp', []).controller('OneController', function() {
this.test = function(element) {
element.css('color', 'red');
}
}).directive('one', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
controller: 'OneController',
template: '<span ng-transclude>And a </span>',
}
}).directive('two', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
require: '^one',
template: '<span ng-transclude>and a </span>',
}
}).directive('three', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
require: '^one',
template: '<span ng-transclude>and a one two</span>',
link: function(scope, element, attrs, ctrl) {
ctrl.test(element);
}
}
});

Resources