-
Notifications
You must be signed in to change notification settings - Fork 27.5k
feat(ngTranscludeSelect): add ng-transclude-select directive for multi-transclusion #11736
Conversation
selectedElements, | ||
transcludeTargets = dirElement[0].querySelectorAll('[ng-transclude-select]'), | ||
cloneWrapper = jqLite("<span></span>"); | ||
cloneWrapper.append(clone); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely code smell, but I couldn't figure out a better way to search the clone by selector. Any suggestions on how to improve?
12d35c2
to
df45ab8
Compare
Hi @kara. Sorry I haven't got round to this yet. Trying to finish up the 1.4.0 issues. |
The ng-translude-select directive allows users to transclude multiple templates into their directive.
@petebacondarwin No problem! Know you've been busy with 1.4. Whenever you have a chance, let me know if you have any suggested changes. There is at least one notable hack (regarding wrapping the clone) that I would love to replace with something better if possible. |
I have added this to the list of things to discuss in our 1.5 planning |
@IgorMinar is going to take a look this week. There have been developments in the WebComponents API that we ought to take into account for this PR perhaps. |
We should consider making the API similar to the SLOT proposal for ShadowDOM: See https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md. |
The thing is that the slotting api style makes the implementation as well as usage of this feature more cumbersome. The only thing we'd gain is similarity with an evolving standard. I don't think that it is worth it in Angular 1. One significant drawback of the current implementation is that it will transclude as many times as many instance of ngTranscludeSelect we find in the components template. This is pretty wasteful and will become a perf issue for bigger apps. Could we address this? It's quite hard to find a good way for this transcluded dom to be shared, since it needs to be accessible from any child node that triggers the ngTranscludeSelect directive, but how about we monkey-patch the |
After talking with @IgorMinar we agreed that some form of slot based algorithm would make it easier to avoid the performance problems. I am going to make a quick spike this week. I can't remember if this is close to what @kara had in her previous PR. If we agree it is viable then perhaps, @kara, you would have time to work on the full implementation? The idea would be that some directive say Example: <my-container>
<div ng-slot="head">This is head content.</div>
<div>This is body content.</div>
<div ng-slot="foot">This is foot content.</div>
</my-container> angular.module('app', [])
.directive('myContainer', function() {
return {
transclude: true,
link: function(scope, element, attr, controller, transcludeFn, transcludeSlots) {
// here the transcludeSlots parameter will look like:
// { head: headTranscludeFn, foot: footTranscludeFn }
// The transcludeFn will contain anything that was not in a slot
// where each function is a pre-bound (to its own transclusion scope) transclude function
},
template: [
'<header ng-transclude="head"></header>',
'<main ng-transclude></main>',
'<footer ng-transclude="foot"></footer>'
].join('')
};
}); |
@IgorMinar @petebacondarwin Thanks for taking a look! The changes you're suggesting make a lot of sense. Yeah, I can definitely make time to rewrite the functionality with the slot implementation you outlined. |
Now you can efficiently split up and transclude content into specified places in a component's template. ```html <pane> <pane-title>Some content for slot A</pane-title> <pane-content>Some content for slot A</pane-content> </component> ``` ```js mod.directive('pane', function() { return { restrict: 'E', transclude: { paneTitle: '?titleSlot', paneContent: 'contentSlot' }, template: '<div class="pane">' + '<h1 ng-transclude="titleSlot"></h1>' + '<div ng-transclude="contentSlot"></div>' + '</div>' + }; }); ``` Closes #4357 Closes #12742 Closes #11736 Closes #12934
I've updated the PR to make the syntax closer to
<content select>
tags (and thus make migration to Angular 2 a bit easier). To transclude in multiple points, you simply:transclude
totrue
ng-transclude-select
directives in your template to mark transcludable sectionsng-transclude-select
selectors.Example usage:
index.html
myContainer.js
The output in the DOM would be something like:
The implementation needs work. There are some hacks like wrapping the clone to use
querySelector
- would love to replace that with something better. Another implementation option would be to do all the matching at once - so you could throw an error at any unused clone elements (currently, they are just being cleaned up).