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

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.

Related

In a named transclude slot, how do I transclude *only* the element's contents?

I've got a basic directive that I want to use transclusion. The relevant options are set up as follows:
restrict: "E",
replace: true,
transclude: {
'toolbar': 'toolbarSlot'
},
scope: {
pageTitle: "#"
},
templateUrl: "path/to/my/template.html"
My template is:
<header class="page-header">
<h1 class="page-title heading">{{ pageTitle }}</h1>
<div class="page-header-toolbar toolbar" ng-transclude="toolbar">
<!-- "toolbar" transcluded content should go here -->
</div>
</header>
And finally, when I use the directive, I'm using it this way:
<my-custom-page-header-directive page-title="Title">
<toolbar-slot>
<button>Button</button>
<button>Another button</button>
</toolbar-slot>
</my-custom-page-header-directive>
The problem is, in the DOM it ends up as something like this, with an extraneous toolbar-slot element mixed into the transcluded content:
<header class="page-header">
<h1 class="page-title heading">Title</h1>
<div class="page-header-toolbar toolbar">
<toolbar-slot>
<button>Button</button>
<button>Another button</button>
</toolbar-slot>
</div>
</header>
Is there a way (using ngTransclude) to only transclude the contents of the slot element?
Looks like the answer is no, there isn't a way to do that as of right now.
An open issue on the Angular.js repository shows that there are misgivings about implementing the ability to use ngTransclude that way:
I'm not a fan of adding a replace functionality to the slot transclusion. It would introduced the same problems we have with normal "replace" and transclude: element.
But, apparently, you "can actually do this manually if your really need it".

Angular Directive placed on ng-repeat not removed from ng-repeat

I have an AngularJS directive meant to interact with notifications pushed from a server. The problem I am having is that currently the method I am using is to have an ng-repeat which keeps track of all the notifications during the session, and then displaying them as they are added to the array. What I want to happen, is that an alert comes, it's added to the DOM, it stays for a couple seconds, and removes itself from the DOM. At this point the issue is that the element will hide, but it will not remove itself from the DOM. Being that the element is absolutely positioned, after the fadeout is prevents me from accessing item that it is in front of. I assumed that element.remove() and the element.$destroy() would do the trick, but it seems like the element is not being from the ng-repeat or possibly that the $scope of the directive is not being deleted. Any help would be greatly appreciated.
angular.module('bmuApp').directive('messageNoti', function($timeout){
return {
scope: {
alert: '=messageNoti'
},
replace: true,
restrict: 'EA',
templateUrl: 'partials/authenticated/homepage/alerts.html',
link: function(scope, element, attrs) {
$timeout(function(){
element.addClass('fadeOut');
$timeout(function(){
element.remove();
}, 500);
}, 5000);
element.on('$destroy', function () {
scope.$destroy();
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!------------>
<!-- Alerts -->
<!------------>
<div class="alert-container" ng-cloak>
<a class="alert animated fadeInUp" ng-repeat="alert in alerts" ng-href="messages/{{ alert.user.thread_id }}" message-noti="alert">
</a>
</div>
<!-----Template for Alert------>
<div class="row">
<span class="close">
<i class="glyphicon glyphicon-remove"></i>
</span>
<div class="col-xs-12 text-left">
<span class="profile-image" style="background-image:url('https://www.blackmarketu.com/{{ ::alert.user['profile-picture'] }}');"></span>
<h5> {{ ::alert.user["user-firstname"] }} {{ ::alert.user["user-lastname"] }} </h5>
<p>{{ ::alert.message }}</p>
</div>
</div>
You don't need to interact with the DOM directly to remove it. Just splice (remove) that array member from the array.
So your logic is a bit wrong, because you have an array of alerts and you are not removing them, you just want to remove the DOM element.
If you don't want to change your code too much and add a parent directive to handle this, you can pass both "alert" (current array member) and "alerts" (entire array of alerts) to your directive and then in your timeout callback instead of removing the DOM element, you splice that array member from the array.
Remove replace: true. Since the ng-repeat directive creates inherited scopes and your directive creates isolate scope, they won't play well together on the same element.
From the Docs:
replace ([DEPRECATED!], will be removed in next major release - i.e. v2.0)
specify what the template should replace. Defaults to false.
true - the template will replace the directive's element.
false - the template will replace the contents of the directive's element.
-- AngularJS Comprehensive Directive API
From GitHub:
Caitp-- It's deprecated because there are known, very silly problems with replace: true, a number of which can't really be fixed in a reasonable fashion. If you're careful and avoid these problems, then more power to you, but for the benefit of new users, it's easier to just tell them "this will give you a headache, don't do it".
-- AngularJS Issue #7636

How do I remove attributes from an element based on an expression in Angular?

I'm working on my portfolio site and I've added a slight parallax effect to my header.
You can see this effect here:
http://claytonkinder.github.io/#/profile
It is VERY unfinished at the moment, so I'd advise only looking at it in Chrome.
This effect lags terribly on mobile devices, so I'm trying to remove all parallax effects from them.
I've got it working by using ng-show to show/hide different headers depending on if my isMobile variable is true or false, but that's a lot of duplicated code and I think it's pretty sloppy.
This is my complete header code:
<header ng-show="!isMobile" parallax-background parallax-ratio="0.2" ng-controller="NavController">
<div>
<div parallax parallax-ratio="1.4" parallax-vertical-offset="0" parallax-horizontal-offset="0">
<h1>Clayton</h1>
</div>
<div parallax parallax-ratio="1.15" parallax-vertical-offset="0" parallax-horizontal-offset="0">
<h1>Kinder</h1>
</div>
</div>
<nav set-class-when-at-top="fixToTop" add-class-when-mobile>
<div class="navWrapper">
<div class="navLeft">
<div>
<span>Clayton Kinder</span>
</div>
<div>
<i class="fa fa-github" title="Github"></i>
<i class="fa fa-phone" title="Phone"></i>
<i class="fa fa-envelope-o" title="Email"></i>
</div>
</div>
<div class="navRight">
<div>
PROFILE
PROJECTS
CONTACT
</div>
</div>
</div>
</nav>
</header>
The mobile version is exactly the same except for lacking all of the parallax-related attributes, meaning that this:
<header ng-show="!isMobile" parallax-background parallax-ratio="0.2" ng-controller="NavController">
becomes this:
<header ng-show="!isMobile">
My question is: what's the best way to get the finished header I'm looking for? Can I add/remove attributes based on an expression? Can I just do ng-show/ng-if on the beginning header tag and two divs that have parallax effects instead of having to copy over the entire header again?
Thank you for any and all help.
You can create a directive which will remove itself and add other directives.
Here's a template for you:
angular
.module('app')
.directive("showWhen", showWhen);
function showWhen($compile, $timeout) {
var directive = {
restrict: 'A',
priority: 1000,
terminal: true,
link: showWhenPostLink
};
function showWhenPostLink(scope, element, attrs) {
var listener = scope.$watch(attrs.showWhen, function(condition) {
if (condition) {
element.removeAttr("show-when"); // to stop infinite loops after $compile
// add directives here, ng-disabled is just an example
element.attr("ng-disabled", "true");
$compile(element)(scope); // $compile all the newly added angular directives
$timeout(function() {
listener(); // unregister the $watch
});
}
})
}
return directive;
}
http://plnkr.co/edit/vnNIRLeW5SvtlVO22SWh?p=preview
Read more # Add directives from directive in AngularJS

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

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.

Angularjs directive removes all content from parent div

I have custom directive declaration with replace set to true.
When I place it in html with separate close tag:
<div>
<search-box search="search(query)" query="query" ></search-box>
<div class="dataDiv">
<!--other div elements -->
</div>
</div>
everything works as expected.
But after rewriting html in this way:
<div>
<search-box search="search(query)" query="query" />
<div class="dataDiv">
<!--other div elements -->
</div>
</div>
directive completely replaces all parent div content with it's template and removes dataDiv from resulting html page.
Is this expected angular behavior or something that can be changed in directive declaration?
Directive:
function SearchBox() {
return {
restrict: 'E',
replace: true,
template: '...',
scope: {
query: '='
},
link: function($scope, $element){
...
},
controller: function ($scope) {
...
}
}
}
Depending on your doctype you might be giving the wrong meaning to the "closing" slash.
by default, yeoman generator and angular-seed use <!doctype html> (html5)
In HTML 5, <foo /> means <foo>. The slash is just syntactic sugar
Check this Are (non-void) self-closing tags valid in HTML5?
Depending on the browser implementation, it will add automatically a closing tag in one place or another, just like when you leave bodyor strong open and read the rendered code.

Categories

Resources