Mustache.js to Angular.js, triple bracers in Angular? - javascript

I have the following in Mustache.js:
<div>{{{icon.tmpl}}}</div>
icon.tmpl is a template on its own with the following content:
<div id="{{id}}" class="glyphicon glyphicon-send"></div>
In Mustache.js, thanks to the triple bracers, this works perfectly, both levels of templates gets compiled. Now I can't make this work in Angular.js. The second embedded template does not get compiled, but is instead surrounded by quotation marks "..."
How to make this work in Angular?

You could either use an ngInclude or create a directive. Here is an example of an icon directive that essentially just replaces any icon element with the div info you've specified.
http://plnkr.co/edit/NK5bOFvsgpMGeTkteMif?p=preview
html:
<icon></icon>
js:
app.directive('icon', function ( $compile, $timeout) {
return {
restrict: 'EA',
replace: true,
template: '<div id="{{id}}" class="glyphicon glyphicon-send"></div>'
}
})
The directive could just as easily be something like <div class="icon"> or <div icon> and you could apply the template to it.
An example of the ngInclude:
<ng-include src="'icon.html'"></ng-include>
Where icon.html just has your template info. Make sure that id is in the scope in both cases.

Related

Transclude example not working for me

I've been taking a look for this tutorial, and now I'm trying to follow it. But somehow, when I reach the following JSBin and paste it all on my test folder, it just won't work:
http://teropa.info/blog/2015/06/09/transclusion.html
You can see at the right side the card showing up perfectly. Well, when I copy paste this code, the content doesn't get rendered inside the "content" div of the template, which means that transclusion isn't working at all.
What may be happening? The code is perfectly pasted, both HTML, CSS and JS. Even tried with my local version of Angular (last one).
But the content keeps being hidden! Any help with this? I really wanna learn how the transclusion works.
Consider I have created a directive called myDirective as an element
<div ng-controller="myCtrl">
<my-directive>
<button>some button</button>
and a link
</my-directive>
</div>
myDirective has a template which is using transclude
myApp.directive('myDirective', function(){
return{
restrict: 'E',
transclude: true,
template: '<div class="something" ng-transclude> my directive goes here...</div>'
}
});
It will render the DOM as
<div class="something">
my directive goes here...
<button>some button</button>
and a link
</div>.

ng-transclude works differently for element and attribute directives [duplicate]

I want to create a wrapper directive that would serve as the frame for a notification widget in a list. In that frame I want to transclude later some specific content based on a property from the notif object. Currently I hard coded a div element.
I have the following in index.cshtml:
<div ng-controller="notificationCenterCtrl">
<ul>
<li ng-repeat="notif in allNotifications">
<notification-base notification="notif" remove="removeNotification(notif)">
<div style="background-color: fuchsia">bla bla</div>
</notification-base>
</li>
</ul>
</div>
This is the directive spec:
ns.directive("notificationBase", function() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: '/Scripts/notification-base.html',
controller: 'notificationBaseCtrl',
scope: {
notification: '=',
removeNotif: '&remove'
}
};
});
Why does the following work, that is it displays the transcluded div in fuchsia background?
<div>
My notification title: {{notification.name}}
<div ng-transclude id="notificationContent">
</div>
<a ng-click="remove()">Remove</a>
</div>
...but if i use it like an element the fuchsia div no longer shows up.
<div>
My notification title: {{notification.name}}
<div id="notificationContent">
<ng-transclude></ng-transclude>
</div>
<a ng-click="remove()">Remove</a>
</div>
What is the difference if I use ng-transclude as an attribute or an element. (I use Firefox).
Only recently (since this pull request) ngTransclude directive supports usage as element.
You are probably using angular with version < 1.3 where ngTransclude used as element is not supported - the primary reason for this being IE8 support.

Recursion in angular directives / templates

I was trying to build a custom directive for displaying a tree. For some reason it seems that once you include the directive in its own template, something runs wild in the angular compiler and the browser process gets stuck in a loop.
Here's a plunker:
<li class="list-group-item">
<a ng-click="clicked(item)"><span ng-if="item.items" class="glyphicon glyphicon-plus text-primary"></span></a>
<span ng-if="!item.items" class="glyphicon glyphicon-record text-primary"></span>
<a>{{item.name}}</a>
<div ng-if="item.items && item.items.length>0">
<ul class="list-group">
<taxonomy-item ng-if="item.items && item.items.length>0" ng-repeat="child in item.items"></taxonomy-item>
</ul>
</div>
If you pay attention you'll see that it doesn't even bind data, so it shouldn't be a recursive loop caused by model/data, but rather a compiler issue...
http://plnkr.co/edit/1aollcuCr2gA96W6Sk6q
Careful, running might freeze your browser tab!
Any suggestions on how to work around this problem?
The solution is quite simple. Since angular doesn't permit the usage of directives within themselves, you need to make use of the link function, to add the child directive afterwards. A minimal example:
myApp.directive("myDirective", ["$compile",function($compile){
var template = '<my-directive ng-repeat="child in item.items" ng-model="child"></my-directive>';
return{
templateUrl: "myDirective.html",
replace: true,
transclude: true,
scope: {
item: "=ngModel"
},
link: function(scope, element){
var compiled = $compile(template)(scope);
element.append(compiled);
}
}
}]);
This won't cause any trouble, since the compiled child directive is self-contained and compiled afterwards.

dynamic directive: templateUrl

I really need help by solving the following problem:
I try to realize some settings for an application, therefore I want to use the UI-Bootstrap accordion.
I have the following HTML-Code:
<accordion close-others="oneAtATime">
<accordion-group ng-repeat="group in groups" heading="{{group.groupTitle}}">
<accordion-content></accordion-content>
</accordion-group>
</accordion>
The DOM of the "accordion" is a div where ng-controller="AccordionController". In this Controller I have a variable groups which looks like this:
$scope.groups = [{
groupTitle: "title1",
templateUrl: "file1.html"
}, {
groupTitle: "title2",
templateUrl: "file2.html"
}]; // ... and so on
accordionContent is my directive which should give different templateURLs depending on the $index or groupTitle (doesn't matter).
The accordionContent-directive looks like this:
settings.directive("accordionContent", function () {
return {
restrict: "E",
templateUrl: //**here is my problem**
};
});
The content also has some angular-stuff implemented, I read that this need to get considered. (or not ?)
I don't believe you can do that like that. I tried myself once, didn't work if I remember correctly.
What you can do is have a static HTML page in the directive, and in that HTML page you'll have:
<div>
<div class="slide-animate" ng-include="templateUrl"></div>
</div>
Where templateUrl is the variable on your isolated scope (or not isolated..) in the accordion-content directive.

Template inside of a directive

I have a strange situation where I need to put a template inside of a template in my directive. The reason for this is that AngularJS will not read ng-repeat code inside of attributes.
In an ideal world, this is what my code would look like:
<div ng-repeat="phone in phones">
<button popover="<div ng-repeat='friend in phone.friends'>{{friend.name}}</div>"></button>
</div>
Unfortunately this does not work because of the quotes around the popover attribute. This has led me down a pretty deep rabbit hole where I'm trying to put a template inside of a template like in this plunker:
http://plnkr.co/edit/ZA1uA1UOlU3cCH2mbE0X?p=preview
HTML:
<div my-popover></div>
Javascript:
angularApp.directive('myPopover', function( $compile) {
var getTemplate = function()
{
var scope = {title: "other title"};
var template = "<div> test template. title: {{title}}</div> ";
return $compile(template)(scope);
}
return {
restrict: 'A',
template: '<button class="btn btn-default" popover="{{content}}" popover-title="title">template</button>',
link: function(scope) {
scope.content = getTemplate();
}
};
})
Unfortunately this does not work because AngularJs complains about a circular reference. Please help! (this has been taking me all day)
I'm not sure I understand exactly what you are trying to achieve, but from the look of it you might want check out the transclude option for directives.
From the docs:
use transclude: true when you want to create a directive that wraps
arbitrary content.
If you use transclude, you can store the popover content inside the button, and "forward" that content to where you want it using the ng-transclude directive.
Your code would then look something like this:
<button>
<div ng-repeat='friend in phone.friends'>{{friend.name}}</div>
</button>
You can see some examples in action in the guide to directives.

Categories

Resources