AngularJS Directive What means Replace and Transclude? - angularjs

Can somebody explains what means:
replace: true / false
and
transclude: true / false
in an angularjs directive?
I did read the documentation but could understand it 100%.

Replace
Whenever you say replace: true, you are telling your directive to replace your directive tag with the template of directive.
Assume you have used template: '<div>This is directive template</div>' in your directive that look like <div data-my-directive></div> When you run your application all the directives div in DOM will be replaced by <div>This is directive template</div>
However in the same scenario if you declare replace: false Your DOM will have something like this
<div data-my-directive>
<div>This is directive template</div>
</div>
TRANSCLUDE
You use ng-transclude, you want to append data in the directive template from controller of your view.
Lets say you have template in your directive which looks like
template: '<div class="main"><div data-ng-transclude></div></div>'
So when you set transclude: true you are explicitly telling your directive to allow all the transcluded values to be part of directive itself when DOM loads.
Lets say you have used the directive in your view like this:
<div data-my-directive>
Transcluded data
</div>
You will see th the text Transcluded data in your web page, however if you have set transclude: false You wont see the text Transcluded data

To keep it simple:
Replace true will replace your directive's template with the tag from where you called your directive:
<my-directive></my-directive>
if replace is true will become:
<div>bla bla</div>
if replace is false will become:
<my-directive><div>bla bla</div></my-directive>
Transclude will "copy" whatever is inside your directive, and append it somewhere on your template:
<my-directive>This is some content</my-directive>
if transclude is true:
<my-directive>
<div>bla bla</div>
<span>This is some content</span> <!--for this to work your template needs to use the ng-transclude directive -->
</my-directive>
if transclude is false:
<my-directive>
<div>bla bla</div>
</my-directive>

Related

ngTransclude directive doesn't work, can't realize where I'm wrong

Trying to use ngTransclude first time to make custom directive, to achieve the floating label functionality as shown here: Floating label pattern — Angular JS, but it doesn't work.
Here is my directive code:
.directive('floatingLabel', function () {
return {
restrict: 'A',
scope: {
label: '#',
value: '='
},
transclude: true,
templateUrl: 'floating-label-template.html'
}}
)
Directive's template:
<div class="field">
<label ng-show="value" class="show-hide">{{label}}</label>
<div ng-transclude></div>
</div>
I'm trying to use it in the following way:
<input floating-label label="Floating" value="floatingDirective" type="text" class="form-control" ng-model="floatingDirective"/>
Plunker with my code: https://plnkr.co/edit/MC8G4H3B9zEleaBZ7ijJ?p=preview
P.S. I'm using AngularJS 1.4.9
Fixed plunker.
Read this : What is ng-transclude
Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
Why your code not working: you have nothing to be 'transclude'.
A general markup of use directive with ng-transclude may like this:
<directive-with-ng-transclude>
<node-to-transclude></node-to-transclude>
</directive-with-ng-transclude>
After compiled, <node-to-transclude></node-to-transclude> will be appended to the template of your directive where you put ng-transclude.
Notice : ng-model inside ng-transclude , that's why I use a dotted ng-model floatingDirective.

Angular JS : replace property in directive

In angular JS, we have a property called replace with possible values as true or false while defining directive. But i dont understand how this property will be used. Will it replace the HTML parent element when it is set true
Actual template:
<div class="parent">
<my-dir><div>Hello world!!</div></my-dir>
</div>
if replace is true, mir-dir tag will be removed.
<div class="parent">
<div>Hello world!!</div>
</div>
if replace is false, mir-dir tag will not be removed.
<div class="parent">
<my-dir><div>Hello world!!</div></my-dir>
</div>
Hope you understand!!. let me know if you have any queries.
Replace - If set to true will replace the element having a directive on it with a template.
PS : You have to use templateUrl/template along with replace.
HTML
<div angular></div>
<div class="angular"></div>
<angular>Simple angular directive</angular>
JS
var App = angular.module('App', []);
App.directive('angular', function() {
return {
restrict: 'ECMA',
replace: true,
template: '<img src="http://goo.gl/ceZGf"/>'
};
});
Above example angular directive will replace its contents "Simple angular directive" by contents in template i.e "Replaced content".
According to the documentation of angular (replace option):
true - the template will replace the directive's element.
false - the template will replace the contents of the directive's element.
Imagine you have a directive named my-directive with the template <span>directive</span> and your html code is <div my-directive></div>. Then replace : false results in:
<div my-directive><span class="replaced" my-directive="">directive</span></div>
And replace : true results in:
<span class="replaced" my-directive="">directive</span>
Please note that this option is deprecated.
See related questions:
How to use `replace` of directive definition?
Explain replace=true in Angular Directives (Deprecated)

angular trasnclude always adds as child, sibling required

I would like to do the transclude equivalent of element.insertAfter. What I am getting is basically element.appendChild. I would like the new element to share the same parent as the directive's element.
I would like
<div>
<input with-button></input>
</div>
to become
<div>
<input></input>
<button></button>
</div>
but I get instead
<div>
<input>
<button></button>
</input>
</div>
My directive's template looks like
<ng-transclude></ng-transclude>
<button></button>
and the directive looks like
angular
.module('appy')
.directive('withButton', withButton);
function withButton() {
return {
restrict: 'A',
transclude: true,
templateUrl: 'path/to/template'
};
}
According to the docs this should work. What am I missing?
First thing, everything you declare as directive template will be put inside the element on which the directive is used. So in your case your template:
<ng-transclude></ng-transclude>
<button></button>
Will go inside the:
<input with-button></input>
So, no wonder the button finishes inside your input.
Second thing, setting { transclude: true } means "get everything from inside the element on which this directive is applied, and put it inside the element in the directive template on which ng-transclude is used", in this case nothing since there is nothing inside
<input with-button></input>
(it has no children).

When to use transclude 'true' and transclude 'element' in Angular?

When should I use transclude: 'true' and when transclude: 'element' ?
I cant find anything about transclude: 'element' in the angular docs, they are pretty confusing.
I would be happy if someone could explain this in simple language.
What is the benefit of each option? What is the real difference between them?
This is what I have found :
transclude: true
Inside a compile function, you can manipulate the DOM with the help of transclude linking function or you can insert the transcluded DOM into the template using ngTransclude directive on any HTML tag.
and
transclude: ‘element’
This transcludes the entire element and a transclude linking function is introduced in the compile function. You can not have access to scope here because the scope is not yet created. Compile function creates a link function for the directive which has access to scope and transcludeFn lets you touch the cloned element (which was transcluded) for DOM manipulation or make use of data bound to scope in it. For your information, this is used in ng-repeat and ng-switch.
From AngularJS Documentation on Directives:
transclude - compile the content of the element and make it available to the directive. Typically used with ngTransclude. The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope. In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope.
true - transclude the content of the directive.
'element' - transclude the whole element including any directives defined at lower priority.
transclude: true
So let's say you have a directive called my-transclude-true declared with transclude: true that looks like this:
<div>
<my-transclude-true>
<span>{{ something }}</span>
{{ otherThing }}
</my-transclude-true>
</div>
After compiling and before linking this becomes:
<div>
<my-transclude-true>
<!-- transcluded -->
</my-transclude-true>
</div>
The content (children) of my-transclude-true which is <span>{{ something }}</span> {{..., is transcluded and available to the directive.
transclude: 'element'
If you have a directive called my-transclude-element declared with transclude: 'element' that looks like this:
<div>
<my-transclude-element>
<span>{{ something }}</span>
{{ otherThing }}
</my-transclude-element>
</div>
After compiling and before linking this becomes:
<div>
<!-- transcluded -->
</div>
Here, the whole element including its children are transcluded and made available to the directive.
What happens after linking?
That's up to your directive to do what it needs to do with the transclude function. ngRepeat uses transclude: 'element' so that it can repeat the whole element and its children when the scope changes. However, if you only need to replace the tag and want to retain it's contents, you can use transclude: true with the ngTransclude directive which does this for you.
When set to true, the
directive will delete the original content, but make it available for reinsertion within
your template through a directive called ng-transclude.
appModule.directive('directiveName', function() {
return {
template: '<div>Hello there <span ng-transclude></span></div>',
transclude: true
};
});
<div directive-name>world</div>
browser render: “Hello there world.”
The best way of think about transclusion is a Picture Frame.A picture frame has its own design and a space for adding the picture.We can decide what picture will go inside of it.
When it comes to angular we have some kind of controller with its scope and inside of that we will place a directive that supports transclusion. This directive will have it’s own display and functionality . In non-transluded directive, content inside the directive is decided by the directive itself but with transclusion,just like a picture frame,we can decide what will be inside the directive.
angular.module("app").directive('myFrame', function () {
return {
restrict: 'E',
templateUrl:"frame.html",
controller:function($scope){
$scope.hidden=false;
$scope.close=function(){
$scope.hidden=true;
}
},
transclude:true
}
});
Content inside the directive
<div class="well" style="width:350px;" ng-hide="hidden">
<div style="float:right;margin-top:-15px">
<i class="glyphicon glyphicon-remove" ng-click="close()" style="cursor:pointer"></i>
</div>
<div ng-transclude>
/*frame content goes here*/
</div>
</div>
Call Directive
<body ng-controller="appController">
<my-frame>
<span>My Frame content</span>
</my-frame>
</body>
Example

Howto set template variables in Angular UI Bootstrap? (accordion)

I try to build a accordion with Angular UI Bootstrap (http://angular-ui.github.io/bootstrap/#/accordion). On How do I set model according to chosen accordion group. UI Bootstrap i found a working solution to use a template.
In my code i add the template with <script type="text/ng-template" id="template/accordion/accordion-group.html">
In this template a can use {{heading}} set by <accordion-group heading="{{group.title}}" content="{{group.content}}" ng-repeat="group in groups"></accordion-group>.
But how do i set other custom template variables?
I tried to set content="{{group.content}}" in the accordion tag too. Even if set, i don't know how to use it, tried {{content.group}} {{content}} and {% content %}.
Complete code on: http://plnkr.co/dSIVGg64vYSTAv5vFSof
See the edited plunker: http://plnkr.co/edit/8YCUemqILQy3knXqwomJ
You were trying to the nest a controller within the template of a directive. I might be mistaken, but that doesn't work or at least not in a very nice manner.
Instead of nesting controllers I would recommend converting CollapseDemoCtrl into a directive too. You can then pass the {{group.content}} or any other content to this directive.
EDIT: Example of how to pass data to directive scope
The HTML will be something like this:
<span ng-repeat="group in groups">
<div testDirective content="group.content" title="group.title"> </div>
</span>
The directive will look something like this:
angular.module('testModule', [])
.directive('testDirective', function(){
return {
restrict: 'A',
scope: {
content:'=content',
title: '=title'
},
template: '<h1>{{title}}<h1> <div>{{content}}</div>',
link: function(scope, element, attrs) {
}
}
});

Resources