AngularJS directive retaining original content - angularjs

I'm totally confused on transclude/replace and directives. I thought I understood but now I'm lost on how to get this particular test case working. From everything I've in the docs, SO, and blogs, it seems like my code below should work. First, some code:
The markup:
<my-directive><h1>My Title</h1></my-directive>
The end result I want:
<my-directive><div class="awesome"><h1>My Title</h1></div></my-directive>
The directive:
myApp.directive('myDirective', function() {
return {
restrict: 'E',
transclude: true,
template: '<div class="awesome"></div>'
}
});
Instead of what I want, I get:
<my-directive><div class="awesome"></div></my-directive>
What am I doing wrong?

To place the transcluded content into the div, add the ng-transclude directive to it...
template: '<div class="awesome" ng-transclude></div>'
Demo - Fiddle

You are missing the "ng-transclude" in the directive template:
<div class="awesome" ng-transculde></div>

Related

Issue with dom manipulation inside Directive link function - Angularjs

I set up a directive as follows:
.directive('ogTakeATour', function() {
return {
restrict: 'E',
replace: true,
templateUrl: '../scripts/directives/TakeATourTemplate.html',
scope: {
content: '#',
uid: '#'
},
link: function(scope) {
angular.element(scope.uid).css("top","250px");
}
};
});
Directive template looks like this:
<div id="{{uid}}" class="tourContainer">
{{content}}
</div>
And this is how I call my directive:
<og-take-a-tour content="Content goes here" uid="menuTour"></og-take-a-tour>
However for some reasons this does not apply the css to the applicable div.
angular.element(scope.uid).css("top","250px");
Why is this? Could it be that the directive does not know what the id of my element is at the time the link function is running? How would I get around this if that is the case?
Angular's jQlite does not support search by id or CSS selector. So change your code like this:
angular.element(document.querySelector('#' + scope.uid)).css("top", "250px");

using ng-bind to define transcluded content on a directive that uses transclusion

Consider some-directive with the following definition object:
{
restrict: "E",
transclude: true,
template: "<div>content: <div ng-transclude></div></div>"
}
I can use it this way:
<some-directive>{{someContent}}</some-directive>
and not surprisingly, someContent will be placed where it has to.
But I want to be able to use it this way also:
<some-directive ng-bind='someContent'></some-directive>
Here is an example of the problem
It's not clear to me why you must use ng-bind over {{ }}, but if you must, then one way to solve this is to transclude the entire element using transclude: "element".
This, however, ignores the template property, so you'd need to manually add it in the compile function. And, you'd need to make the priority of your directive higher than that of ngBind (which has the default priority 1):
return{
restrict: "E",
transclude: "element",
priority: 10,
compile: function(tElem, tAttrs){
var template = "\
<div class='some-directive'>\
<div class='some-directive-header'>My custom component</div>\
<div class='some-directive-body' ng-transclude></div>\
</div>";
tElem.replaceWith(template);
}
};
Your forked plunker
This fixes your example:
<some-directive ><span ng-bind='someContent' /></some-directive>
http://plnkr.co/edit/qwKFYv1WAbpPTR1gGuqA?p=preview

Different scope when using ng-repeat and custom directive in one element

I have a directive like:
angular.module('myApp').directive('myDirective', function() {
return {
templateUrl: '/views/myView.html',
restrict: 'E',
link: function (scope, element, attrs) {
console.log(scope);
console.log(angular.element(element).scope());
}
};
});
the template html is:
<div>{{item.text}}</div>
and view html is:
<div ng-init="items=[{text:'hello'}, {text: 'world'}]">
<my-directive ng-repeat="item in items"></my-directive>
</div>
I find the scope and angular.element(element).scope() is not the same one, but I have to use angular.element(element).scope() way to get the scope of ngRepeat-item somewhere else.
Am I misunderstanding something?
Note:
The code could be reproduced only when including jQuery.
Here is related github issue.
The main reason is: angular1.2.x does not support jQuery2.0.x, and angular1.3.x will do.
So the solution here will be:
angular1.2.x + jQuery 1.x
angular1.3.x + jQuery 2.x
angularjs only

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.

When using two way binding in angular, when are the binded variables actually available?

I'm writing a directive that uses two-way binding.My directive looks like this:
bankSearch.directive('bankSearch',
function() {
return {
restrict: 'E',
scope: {
bankDetail: '='
},
templateUrl: "angular/views/self_signup/bank_search.html",
link: function(scope) {
//Now when link function runs, scope.bankDetail is undefined.
}
}
});
Html of template-url:
`<div class="row-fluid">
<input id="ifsc-code" class="span12" type="text" name="ifscCode"
ng-model="bankDetail.bankBranch.ifscCode"
should-be-ifsc
ng-keypress="onPressEnter($event, bankSearch.ifscCode.$valid)">
</div>`
This is how I'm using the directive:
`<bank-search
bank-detail="bankSearchModel.bankDetail">
</bank-search>`
I was under the impression that link function runs after linking(watchers setup) is done. If I'm correct then why am I getting undefined for scope.bankDetail inside my link function.
I'm new to Angular. Thanks for the help!
Might be bankSearchModel.bankDetail defines after directive is rendered. In case it is loaded from $http or something else. Try
link: function(scope) {
scope.$watch('bankDetail', function(val){
console.log(val);
});
}
And you'll see all changes of that variable.

Resources