Skip to content

Commit 391d8c0

Browse files
docs($compile): improve transclusion documentation
Closes angular#9352
1 parent 11c7636 commit 391d8c0

File tree

1 file changed

+120
-17
lines changed

1 file changed

+120
-17
lines changed

src/ng/compile.js

+120-17
Original file line numberDiff line numberDiff line change
@@ -294,29 +294,17 @@
294294
* (because SVG doesn't work with custom elements in the DOM tree).
295295
*
296296
* #### `transclude`
297-
* compile the content of the element and make it available to the directive.
298-
* Typically used with {@link ng.directive:ngTransclude
299-
* ngTransclude}. The advantage of transclusion is that the linking function receives a
300-
* transclusion function which is pre-bound to the scope of the position in the DOM from where
301-
* it was taken.
297+
* Extract the contents of the element where the directive appears and make it available to the directive.
298+
* The contents are compiled and provided to the directive as a **transclusion function**. See the
299+
* {@link $compile#transclusion Transclusion} section below.
302300
*
303-
* In a typical setup the widget creates an `isolate` scope, but the transcluded
304-
* content has its own **transclusion scope**. While the **transclusion scope** is owned as a child,
305-
* by the **isolate scope**, it prototypically inherits from the original scope from where the
306-
* transcluded content was taken.
307-
*
308-
* This makes it possible for the widget to have private state, and the transclusion to
309-
* be bound to the original (pre-`isolate`) scope.
301+
* There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
302+
* directive's element or the entire element:
310303
*
311304
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
312305
* * `'element'` - transclude the whole of the directive's element including any directives on this
313306
* element that defined at a lower priority than this directive.
314307
*
315-
* <div class="alert alert-warning">
316-
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
317-
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
318-
* Testing Transclusion Directives}.
319-
* </div>
320308
*
321309
* #### `compile`
322310
*
@@ -414,6 +402,121 @@
414402
* It is safe to do DOM transformation in the post-linking function on elements that are not waiting
415403
* for their async templates to be resolved.
416404
*
405+
*
406+
* ### Transclusion
407+
*
408+
* Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
409+
* copying them to another part of the DOM, while maintaining their connection to the original AngularJS
410+
* scope from where they were taken.
411+
*
412+
* Transclusion is used (often with {@link ngTransclude}) to insert the
413+
* original contents of a directive's element into a specified place in the template of the directive.
414+
* The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
415+
* content has access to the properties on the scope from which it was taken, even if the directive
416+
* has isolated scope.
417+
* See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
418+
*
419+
* This makes it possible for the widget to have private state for its template, while the transcluded
420+
* content has access to its originating scope.
421+
*
422+
* <div class="alert alert-warning">
423+
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
424+
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
425+
* Testing Transclusion Directives}.
426+
* </div>
427+
*
428+
* #### Transclusion Functions
429+
*
430+
* When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
431+
* function** to the directive's `link` function and `controller`. This transclusion function is a special
432+
* **linking function** that will return the compiled contents linked to a new transclusion scope.
433+
*
434+
* <div class="alert alert-info">
435+
* If you are just using {@link ngTransclude} then you don't need to worry about this function, since
436+
* ngTransclude will deal with it for us.
437+
* </div>
438+
*
439+
* If you want to manually control the insertion and removal of the transcluded content in your directive
440+
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
441+
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
442+
*
443+
* When you call a transclusion function you can pass in a **clone attach function**. This function is accepts
444+
* two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
445+
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
446+
*
447+
* <div class="alert alert-info">
448+
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
449+
* since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
450+
* </div>
451+
*
452+
* It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
453+
* attach function**:
454+
*
455+
* ```js
456+
* var transcludedContent, transclusionScope;
457+
*
458+
* $transclude(function(clone, scope) {
459+
* element.append(clone);
460+
* transcludedContent = clone;
461+
* transclusionScope = scope;
462+
* });
463+
* ```
464+
*
465+
* Later, if you want to remove the transcluded content from your DOM then you should also destroy the
466+
* associated transclusion scope:
467+
*
468+
* ```js
469+
* transcludedContent.remove();
470+
* transclusionScope.$destroy();
471+
* ```
472+
*
473+
* <div class="alert alert-info">
474+
* **Best Practice**: if you intend to add and remove transcluded content manually in your directive
475+
* (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
476+
* then you are also responsible for calling `$destroy` on the transclusion scope.
477+
* </div>
478+
*
479+
* The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
480+
* automatically destroy their transluded clones as necessary so you do not need to worry about this if
481+
* you are simply using {@link ngTransclude} to inject the transclusion into your directive.
482+
*
483+
*
484+
* #### Transclusion Scopes
485+
*
486+
* When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
487+
* scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
488+
* when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
489+
* was taken.
490+
*
491+
* For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
492+
* like this:
493+
*
494+
* ```html
495+
* <div ng-app>
496+
* <div isolate>
497+
* <div transclusion>
498+
* </div>
499+
* </div>
500+
* </div>
501+
* ```
502+
*
503+
* The `$parent` scope hierarchy will look like this:
504+
*
505+
* ```
506+
* - $rootScope
507+
* - isolate
508+
* - transclusion
509+
* ```
510+
*
511+
* but the scopes will inherit prototypically from different scopes to their `$parent`.
512+
*
513+
* ```
514+
* - $rootScope
515+
* - transclusion
516+
* - isolate
517+
* ```
518+
*
519+
*
417520
* ### Attributes
418521
*
419522
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the

0 commit comments

Comments
 (0)