How can I create a directive that contains other directives? - angularjs

I have created some new directives like this:
<admin-retrieve-button></admin-retrieve-button>
<admin-new-button></admin-new-button>
<admin-save-button></admin-save-button>
<admin-reset-button></admin-reset-button>
Is there a way I can create another directive that combines all of these?

you can use ng-transclude for that
app.directive("adminButtonGroup", function(){
return {
restrict: 'E'
transclude: true,
template: '<div class="btn-group"><div ng-transclude=""></div></div>'
}
});
OR if you do not want to transclude and have fixed set of buttons then
app.directive("adminButtonGroup", function(){
return {
restrict: 'E';
template: '<admin-retrieve-button></admin-retrieve-button>' +
'<admin-new-button></admin-new-button>' +
'<admin-save-button></admin-save-button>' +
'<admin-reset-button></admin-reset-button';
}
});
also you can use require, if your child button wants to speak with parent button.

Yes.
Create a template that contains theses tags, which is then used in your new directive by setting the templateUrl property to the path to the template file.

Related

Directive Element Not displaying directive name in mark up

I want to hide the Directive name markup from my html
Right now I am doing this
<option-found-address-display></option-found-address-display>
But when this renders/compiles I just want to show the contents of the directive. Not the actual <option-found-address-display>and then my content within.
I am pretty sure I saw a way how to hide this but can't remember
app.directive('optionFoundAddressDisplay', function() {
return {
restrict: 'E',
template: '<div>your content</div>',
replace:true
}
});
will hide the directive name markup from the html.
Replace:true does the trick.
For more about replace:true

Angularjs: access template in directive

What I want to do is to append compiled template to some other DOM element in Angualrjs directive. Is it possible? How?
I know you can use transclude to include the template and keep content in the tag, but how do I attach my compiled template to other DOM element?
angular.module("my.directive")
.directive('passwordStrength', [function(){
return {
templateUrl: '/tpl/directive/passwordStrength.html',
restrict: 'A',
link: function postLink(scope, iElement, iAttrs){
console.log('password strength is running');
iElement.append($template) // problem here!!!
}
};
}]);
I'm not sure what you're trying to accomplish overall. You may want to use ng-include to pull in markup from a url, rather than using the templateUrl property, or you may want to use the templateUrl property on one directive, then make another directive and include that directive in the second directive. I made some sample directives to help give you ideas.
.directive('myDirective', function($compile) {
return {
scope: {
path: '=myDirective'
},
link: function(scope, element) {
// rather than use `templateUrl`, I'll get markup from the path using `ng-include`
var html = '<div ng-include="path"></div>';
// manipulate the markup however you want to
html+= '<p>More stuff from "myDirective"!</p>';
// append the markup
element.append(html);
// compile the markup so that Angular will know about it (or use the directive `compile` rather than `link`)
$compile(element.contents())(scope);
}
};
})
// this is sort of like "extending" the other directive.
.directive('myOtherDirective', function() {
return {
scope: {
path: '=myOtherDirective'
},
template: '<p>Stuff from "myOtherDirective"></div><div my-directive="path"></div>'
};
})
Here's a demo you can mess around with.

how to communicate from one directive to another directive

I have tow directives one is for ng-grid another is for pagination when I click page numbers in one directive ng-grid directive should be changed according to that, can I have any idea on that.
There are many ways to achieve it:
For example:
First solution
You can share data between directives:
<directive-one attribute="value" other-attribute="value2" shared-variable="yourData">
<directive-two shared-variable="yourData">
And set $watch inside first directive on that value
scope.$watch('yourData',function(newVal,oldVal){ //your logic called after change });
Second solution
You can use events:
app.directive('first',function(){
return{
restrict: 'E',
template: 'Im first directive!',
scope: true,
link:function(scope,elem,attrs){
scope.$on('event',function(event,args){
alert(args);
});
}
}
});
app.directive('second',function($rootScope){
return{
restrict: 'E',
template: 'Im second directive! <button ng-click="click()">click me!</button>',
scope: true,
link:function(scope,elem,attrs){
scope.click = function(){
$rootScope.$broadcast('event','hello!');
};
}
}
});
Event is sent by $rootScope.$broadcast('event','hello!');. It means event is sent by your root scope downwards to child scopes. http://jsfiddle.net/aartek/fJs69/

What is ng-transclude?

I have seen a number of questions on StackOverflow discussing ng-transclude, but none explaining in layman's terms what it is.
The description in the documentation is as follows:
Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
This is fairly confusing. Would someone be able to explain in simple terms what ng-transclude is intended to do and where it might be used?
Transclude is a setting to tell angular to capture everything that is put inside the directive in the markup and use it somewhere(Where actually the ng-transclude is at) in the directive's template. Read more about this under Creating a Directive that Wraps Other Elements section on documentation of directives.
If you write a custom directive you use ng-transclude in the directive template to mark the point where you want to insert the contents of the element
angular.module('app', [])
.directive('hero', function () {
return {
restrict: 'E',
transclude: true,
scope: { name:'#' },
template: '<div>' +
'<div>{{name}}</div><br>' +
'<div ng-transclude></div>' +
'</div>'
};
});
If you put this in your markup
<hero name="superman">Stuff inside the custom directive</hero>
It would show up like:
Superman
Stuff inside the custom directive
Full example :
Index.html
<body ng-app="myApp">
<div class="AAA">
<hero name="superman">Stuff inside the custom directive</hero>
</div>
</body>
jscript.js
angular.module('myApp', []).directive('hero', function () {
return {
restrict: 'E',
transclude: true,
scope: { name:'#' },
template: '<div>' +
'<div>{{name}}</div><br>' +
'<div ng-transclude></div>' +
'</div>'
};
});
Output markup
Visualize :
For those who come from React world, this is like React's {props.children}.
it's a kind of yield, everything from the element.html() gets rendered there but the directive attributes still visible in the certain scope.

Binding To Element Text In AngularJS

Is it possible to bind to the text of an element without actually dropping into the link function?
<blink>Text Here or {{ controllerText() }}</blink>
// add a namespace for custom directives
angular.module('mydirectives', []);
angular.module('mydirectives').directive('blink', function() {
return {
restrict: 'E',
template: '<marquee scrollamount="100%">{{ can i do it here? }} </marquee>',
scope: {
// can i do it here?
}
};
});
So this is done with transclusion which merges the content of the original element with the template. The ng-transclude tag in the template is required to get it to work.
<blink>Bring the blink back<blink>
// add a namespace for custom directives
angular.module('mydirectives', []);
angular.module('mydirectives').directive('blink', function() {
return {
restrict: 'E',
transclude: true,
template: '<marquee scrollamount="100%" ng-transclude></marquee>'
}
});
You absolute can.
scope: {
text: '='
}
This adds a text attribute to the isolate scope that is linked to the value of the text attribute from the element.
So you need to change the html slightly to:
<blink text="fromController"></blink>
And then add that fromController attribute in the enclosing controller.
Here's a (very annoying) fiddle.

Resources