` => `["foo", -1, "bar", directiveIdx]`
379 | */
380 | localNames: (string|number)[]|null;
381 |
382 | /** Information about input properties that need to be set once from attribute data. */
383 | initialInputs: InitialInputData|null|undefined;
384 |
385 | /**
386 | * Input data for all directives on this node. `null` means that there are no directives with
387 | * inputs on this node.
388 | */
389 | inputs: PropertyAliases|null;
390 |
391 | /**
392 | * Output data for all directives on this node. `null` means that there are no directives with
393 | * outputs on this node.
394 | */
395 | outputs: PropertyAliases|null;
396 |
397 | /**
398 | * The TView or TViews attached to this node.
399 | *
400 | * If this TNode corresponds to an LContainer with inline views, the container will
401 | * need to store separate static data for each of its view blocks (TView[]). Otherwise,
402 | * nodes in inline views with the same index as nodes in their parent views will overwrite
403 | * each other, as they are in the same template.
404 | *
405 | * Each index in this array corresponds to the static data for a certain
406 | * view. So if you had V(0) and V(1) in a container, you might have:
407 | *
408 | * [
409 | * [{tagName: 'div', attrs: ...}, null], // V(0) TView
410 | * [{tagName: 'button', attrs ...}, null] // V(1) TView
411 | *
412 | * If this TNode corresponds to an LContainer with a template (e.g. structural
413 | * directive), the template's TView will be stored here.
414 | *
415 | * If this TNode corresponds to an element, tViews will be null .
416 | */
417 | tViews: TView|TView[]|null;
418 |
419 | /**
420 | * The next sibling node. Necessary so we can propagate through the root nodes of a view
421 | * to insert them or remove them from the DOM.
422 | */
423 | next: TNode|null;
424 |
425 | /**
426 | * The next projected sibling. Since in Angular content projection works on the node-by-node basis
427 | * the act of projecting nodes might change nodes relationship at the insertion point (target
428 | * view). At the same time we need to keep initial relationship between nodes as expressed in
429 | * content view.
430 | */
431 | projectionNext: TNode|null;
432 |
433 | /**
434 | * First child of the current node.
435 | *
436 | * For component nodes, the child will always be a ContentChild (in same view).
437 | * For embedded view nodes, the child will be in their child view.
438 | */
439 | child: TNode|null;
440 |
441 | /**
442 | * Parent node (in the same view only).
443 | *
444 | * We need a reference to a node's parent so we can append the node to its parent's native
445 | * element at the appropriate time.
446 | *
447 | * If the parent would be in a different view (e.g. component host), this property will be null.
448 | * It's important that we don't try to cross component boundaries when retrieving the parent
449 | * because the parent will change (e.g. index, attrs) depending on where the component was
450 | * used (and thus shouldn't be stored on TNode). In these cases, we retrieve the parent through
451 | * LView.node instead (which will be instance-specific).
452 | *
453 | * If this is an inline view node (V), the parent will be its container.
454 | */
455 | parent: TElementNode|TContainerNode|null;
456 |
457 | /**
458 | * List of projected TNodes for a given component host element OR index into the said nodes.
459 | *
460 | * For easier discussion assume this example:
461 | * `
`'s view definition:
462 | * ```
463 | * content1
464 | * content2
465 | * ```
466 | * ``'s view definition:
467 | * ```
468 | *
469 | * ```
470 | *
471 | * If `Array.isArray(projection)` then `TNode` is a host element:
472 | * - `projection` stores the content nodes which are to be projected.
473 | * - The nodes represent categories defined by the selector: For example:
474 | * `` would represent the heads for ``
475 | * and `` respectively.
476 | * - The nodes we store in `projection` are heads only, we used `.next` to get their
477 | * siblings.
478 | * - The nodes `.next` is sorted/rewritten as part of the projection setup.
479 | * - `projection` size is equal to the number of projections ``. The size of
480 | * `c1` will be `1` because `` has only one ``.
481 | * - we store `projection` with the host (`c1`, `c2`) rather than the `` (`cont1`)
482 | * because the same component (``) can be used in multiple locations (`c1`, `c2`) and as
483 | * a result have different set of nodes to project.
484 | * - without `projection` it would be difficult to efficiently traverse nodes to be projected.
485 | *
486 | * If `typeof projection == 'number'` then `TNode` is a `` element:
487 | * - `projection` is an index of the host's `projection`Nodes.
488 | * - This would return the first head node to project:
489 | * `getHost(currentTNode).projection[currentTNode.projection]`.
490 | * - When projecting nodes the parent node retrieved may be a `` node, in which case
491 | * the process is recursive in nature.
492 | *
493 | * If `projection` is of type `RNode[][]` than we have a collection of native nodes passed as
494 | * projectable nodes during dynamic component creation.
495 | */
496 | projection: (TNode|RNode[])[]|number|null;
497 |
498 | /**
499 | * A collection of all style static values for an element.
500 | *
501 | * This field will be populated if and when:
502 | *
503 | * - There are one or more initial styles on an element (e.g. ``)
504 | */
505 | styles: string|null;
506 |
507 | /**
508 | * A `KeyValueArray` version of residual `styles`.
509 | *
510 | * When there are styling instructions than each instruction stores the static styling
511 | * which is of lower priority than itself. This means that there may be a higher priority styling
512 | * than the instruction.
513 | *
514 | * Imagine:
515 | * ```
516 | *
517 | *
518 | * @Directive({
519 | * host: {
520 | * style: 'color: lowest; ',
521 | * '[styles.color]': 'exp' // ɵɵstyleProp('color', ctx.exp);
522 | * }
523 | * })
524 | * ```
525 | *
526 | * In the above case:
527 | * - `color: lowest` is stored with `ɵɵstyleProp('color', ctx.exp);` instruction
528 | * - `color: highest` is the residual and is stored here.
529 | *
530 | * - `undefined': not initialized.
531 | * - `null`: initialized but `styles` is `null`
532 | * - `KeyValueArray`: parsed version of `styles`.
533 | */
534 | residualStyles: any|undefined|null;
535 |
536 | /**
537 | * A collection of all class static values for an element.
538 | *
539 | * This field will be populated if and when:
540 | *
541 | * - There are one or more initial classes on an element (e.g. `
`)
542 | */
543 | classes: string|null;
544 |
545 | /**
546 | * A `KeyValueArray` version of residual `classes`.
547 | *
548 | * Same as `TNode.residualStyles` but for classes.
549 | *
550 | * - `undefined': not initialized.
551 | * - `null`: initialized but `classes` is `null`
552 | * - `KeyValueArray`: parsed version of `classes`.
553 | */
554 | residualClasses: any|undefined|null;
555 |
556 | /**
557 | * Stores the head/tail index of the class bindings.
558 | *
559 | * - If no bindings, the head and tail will both be 0.
560 | * - If there are template bindings, stores the head/tail of the class bindings in the template.
561 | * - If no template bindings but there are host bindings, the head value will point to the last
562 | * host binding for "class" (not the head of the linked list), tail will be 0.
563 | *
564 | * See: `style_binding_list.ts` for details.
565 | *
566 | * This is used by `insertTStylingBinding` to know where the next styling binding should be
567 | * inserted so that they can be sorted in priority order.
568 | */
569 | classBindings: any;
570 |
571 | /**
572 | * Stores the head/tail index of the class bindings.
573 | *
574 | * - If no bindings, the head and tail will both be 0.
575 | * - If there are template bindings, stores the head/tail of the style bindings in the template.
576 | * - If no template bindings but there are host bindings, the head value will point to the last
577 | * host binding for "style" (not the head of the linked list), tail will be 0.
578 | *
579 | * See: `style_binding_list.ts` for details.
580 | *
581 | * This is used by `insertTStylingBinding` to know where the next styling binding should be
582 | * inserted so that they can be sorted in priority order.
583 | */
584 | styleBindings: any;
585 | }
586 |
587 | /** Static data for an element */
588 | export interface TElementNode extends TNode {
589 | /** Index in the data[] array */
590 | index: number;
591 | child: TElementNode|TTextNode|TElementContainerNode|TContainerNode|TProjectionNode|null;
592 | /**
593 | * Element nodes will have parents unless they are the first node of a component or
594 | * embedded view (which means their parent is in a different view and must be
595 | * retrieved using viewData[HOST_NODE]).
596 | */
597 | parent: TElementNode|TElementContainerNode|null;
598 | tViews: null;
599 |
600 | /**
601 | * If this is a component TNode with projection, this will be an array of projected
602 | * TNodes or native nodes (see TNode.projection for more info). If it's a regular element node or
603 | * a component without projection, it will be null.
604 | */
605 | projection: (TNode|RNode[])[]|null;
606 | }
607 |
608 | /** Static data for a text node */
609 | export interface TTextNode extends TNode {
610 | /** Index in the data[] array */
611 | index: number;
612 | child: null;
613 | /**
614 | * Text nodes will have parents unless they are the first node of a component or
615 | * embedded view (which means their parent is in a different view and must be
616 | * retrieved using LView.node).
617 | */
618 | parent: TElementNode|TElementContainerNode|null;
619 | tViews: null;
620 | projection: null;
621 | }
622 |
623 | /** Static data for an LContainer */
624 | export interface TContainerNode extends TNode {
625 | /**
626 | * Index in the data[] array.
627 | *
628 | * If it's -1, this is a dynamically created container node that isn't stored in
629 | * data[] (e.g. when you inject ViewContainerRef) .
630 | */
631 | index: number;
632 | child: null;
633 |
634 | /**
635 | * Container nodes will have parents unless:
636 | *
637 | * - They are the first node of a component or embedded view
638 | * - They are dynamically created
639 | */
640 | parent: TElementNode|TElementContainerNode|null;
641 | tViews: TView|TView[]|null;
642 | projection: null;
643 | }
644 |
645 | /** Static data for an
*/
646 | export interface TElementContainerNode extends TNode {
647 | /** Index in the LView[] array. */
648 | index: number;
649 | child: TElementNode|TTextNode|TContainerNode|TElementContainerNode|TProjectionNode|null;
650 | parent: TElementNode|TElementContainerNode|null;
651 | tViews: null;
652 | projection: null;
653 | }
654 |
655 | /** Static data for an ICU expression */
656 | export interface TIcuContainerNode extends TNode {
657 | /** Index in the LView[] array. */
658 | index: number;
659 | child: TElementNode|TTextNode|null;
660 | parent: TElementNode|TElementContainerNode|null;
661 | tViews: null;
662 | projection: null;
663 | /**
664 | * Indicates the current active case for an ICU expression.
665 | * It is null when there is no active case.
666 | */
667 | activeCaseIndex: number|null;
668 | }
669 |
670 | /** Static data for a view */
671 | export interface TViewNode extends TNode {
672 | /** If -1, it's a dynamically created view. Otherwise, it is the view block ID. */
673 | index: number;
674 | child: TElementNode|TTextNode|TElementContainerNode|TContainerNode|TProjectionNode|null;
675 | parent: TContainerNode|null;
676 | tViews: null;
677 | projection: null;
678 | }
679 |
680 | /** Static data for an LProjectionNode */
681 | export interface TProjectionNode extends TNode {
682 | /** Index in the data[] array */
683 | child: null;
684 | /**
685 | * Projection nodes will have parents unless they are the first node of a component
686 | * or embedded view (which means their parent is in a different view and must be
687 | * retrieved using LView.node).
688 | */
689 | parent: TElementNode|TElementContainerNode|null;
690 | tViews: null;
691 |
692 | /** Index of the projection node. (See TNode.projection for more info.) */
693 | projection: number;
694 | }
695 |
696 | /**
697 | * A union type representing all TNode types that can host a directive.
698 | */
699 | export type TDirectiveHostNode = TElementNode | TContainerNode | TElementContainerNode;
700 |
701 | /**
702 | * This mapping is necessary so we can set input properties and output listeners
703 | * properly at runtime when property names are minified or aliased.
704 | *
705 | * Key: unminified / public input or output name
706 | * Value: array containing minified / internal name and related directive index
707 | *
708 | * The value must be an array to support inputs and outputs with the same name
709 | * on the same node.
710 | */
711 | export type PropertyAliases = {
712 | // This uses an object map because using the Map type would be too slow
713 | [key: string]: PropertyAliasValue
714 | };
715 |
716 | /**
717 | * Store the runtime input or output names for all the directives.
718 | *
719 | * i+0: directive instance index
720 | * i+1: privateName
721 | *
722 | * e.g. [0, 'change-minified']
723 | */
724 | export type PropertyAliasValue = (number | string)[];
725 |
726 | /**
727 | * This array contains information about input properties that
728 | * need to be set once from attribute data. It's ordered by
729 | * directive index (relative to element) so it's simple to
730 | * look up a specific directive's initial input data.
731 | *
732 | * Within each sub-array:
733 | *
734 | * i+0: attribute name
735 | * i+1: minified/internal input name
736 | * i+2: initial value
737 | *
738 | * If a directive on a node does not have any input properties
739 | * that should be set from attributes, its index is set to null
740 | * to avoid a sparse array.
741 | *
742 | * e.g. [null, ['role-min', 'minified-input', 'button']]
743 | */
744 | export type InitialInputData = (InitialInputs | null)[];
745 |
746 | /**
747 | * Used by InitialInputData to store input properties
748 | * that should be set once from attributes.
749 | *
750 | * i+0: attribute name
751 | * i+1: minified/internal input name
752 | * i+2: initial value
753 | *
754 | * e.g. ['role-min', 'minified-input', 'button']
755 | */
756 | export type InitialInputs = string[];
757 |
758 | // Note: This hack is necessary so we don't erroneously get a circular dependency
759 | // failure based on types.
760 | export const unusedValueExportToPlacateAjd = 1;
761 |
762 | /**
763 | * Type representing a set of TNodes that can have local refs (`#foo`) placed on them.
764 | */
765 | export type TNodeWithLocalRefs = TContainerNode | TElementNode | TElementContainerNode;
766 |
767 | /**
768 | * Type for a function that extracts a value for a local refs.
769 | * Example:
770 | * - `` - `nativeDivEl` should point to the native `
` element;
771 | * - `
` - `tplRef` should point to the `TemplateRef` instance;
772 | */
773 | export type LocalRefExtractor = (tNode: TNodeWithLocalRefs, currentView: LView) => any;
774 |
775 | /**
776 | * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding.
777 | *
778 | * ```
779 | *
780 | * ```
781 | * and
782 | * ```
783 | * @Directive({
784 | * })
785 | * class MyDirective {
786 | * @Input()
787 | * class: string;
788 | * }
789 | * ```
790 | *
791 | * In the above case it is necessary to write the reconciled styling information into the
792 | * directive's input.
793 | *
794 | * @param tNode
795 | */
796 | export function hasClassInput(tNode: TNode) {
797 | return (tNode.flags & TNodeFlags.hasClassInput) !== 0;
798 | }
799 |
800 | /**
801 | * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
802 | *
803 | * ```
804 | *
805 | * ```
806 | * and
807 | * ```
808 | * @Directive({
809 | * })
810 | * class MyDirective {
811 | * @Input()
812 | * class: string;
813 | * }
814 | * ```
815 | *
816 | * In the above case it is necessary to write the reconciled styling information into the
817 | * directive's input.
818 | *
819 | * @param tNode
820 | */
821 | export function hasStyleInput(tNode: TNode) {
822 | return (tNode.flags & TNodeFlags.hasStyleInput) !== 0;
823 | }
824 |
--------------------------------------------------------------------------------
/packages/core/angular/interfaces/view.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright Google Inc. All Rights Reserved.
4 | *
5 | * Use of this source code is governed by an MIT-style license that can be
6 | * found in the LICENSE file at https://angular.io/license
7 | */
8 |
9 |
10 | import {LContainer} from './container';
11 | import {TConstants, TElementNode, TNode, TViewNode} from './node';
12 | import {PlayerHandler} from './player';
13 | import {RElement, Renderer3, RendererFactory3} from './renderer';
14 | import {
15 | ComponentDef,
16 | ComponentTemplate,
17 | DirectiveDef,
18 | DirectiveDefList,
19 | PipeDef,
20 | PipeDefList,
21 | ViewQueriesFunction
22 | } from "./definition";
23 | import { InjectionToken, SchemaMetadata, Type } from "@angular/core";
24 |
25 |
26 |
27 | // Below are constants for LView indices to help us look up LView members
28 | // without having to remember the specific indices.
29 | // Uglify will inline these when minifying so there shouldn't be a cost.
30 | export const HOST = 0;
31 | export const TVIEW = 1;
32 | export const FLAGS = 2;
33 | export const PARENT = 3;
34 | export const NEXT = 4;
35 | export const QUERIES = 5;
36 | export const T_HOST = 6;
37 | export const CLEANUP = 7;
38 | export const CONTEXT = 8;
39 | export const INJECTOR = 9;
40 | export const RENDERER_FACTORY = 10;
41 | export const RENDERER = 11;
42 | export const SANITIZER = 12;
43 | export const CHILD_HEAD = 13;
44 | export const CHILD_TAIL = 14;
45 | export const DECLARATION_VIEW = 15;
46 | export const DECLARATION_COMPONENT_VIEW = 16;
47 | export const DECLARATION_LCONTAINER = 17;
48 | export const PREORDER_HOOK_FLAGS = 18;
49 | /** Size of LView's header. Necessary to adjust for it when setting slots. */
50 | export const HEADER_OFFSET = 19;
51 |
52 |
53 | // This interface replaces the real LView interface if it is an arg or a
54 | // return value of a public instruction. This ensures we don't need to expose
55 | // the actual interface, which should be kept private.
56 | export interface OpaqueViewState {
57 | '__brand__': 'Brand for OpaqueViewState that nothing will match';
58 | }
59 |
60 |
61 | /**
62 | * `LView` stores all of the information needed to process the instructions as
63 | * they are invoked from the template. Each embedded view and component view has its
64 | * own `LView`. When processing a particular view, we set the `viewData` to that
65 | * `LView`. When that view is done processing, the `viewData` is set back to
66 | * whatever the original `viewData` was before (the parent `LView`).
67 | *
68 | * Keeping separate state for each view facilities view insertion / deletion, so we
69 | * don't have to edit the data array based on which views are present.
70 | */
71 | export interface LView extends Array {
72 | /**
73 | * The host node for this LView instance, if this is a component view.
74 | * If this is an embedded view, HOST will be null.
75 | */
76 | [HOST]: Element|null;
77 |
78 | /**
79 | * The static data for this view. We need a reference to this so we can easily walk up the
80 | * node tree in DI and get the TView.data array associated with a node (where the
81 | * directive defs are stored).
82 | */
83 | readonly[TVIEW]: TView;
84 |
85 | /** Flags for this view. See LViewFlags for more info. */
86 | [FLAGS]: LViewFlags;
87 |
88 | /**
89 | * This may store an {@link LView} or {@link LContainer}.
90 | *
91 | * `LView` - The parent view. This is needed when we exit the view and must restore the previous
92 | * LView. Without this, the render method would have to keep a stack of
93 | * views as it is recursively rendering templates.
94 | *
95 | * `LContainer` - The current view is part of a container, and is an embedded view.
96 | */
97 | [PARENT]: LView|LContainer|null;
98 |
99 | /**
100 | *
101 | * The next sibling LView or LContainer.
102 | *
103 | * Allows us to propagate between sibling view states that aren't in the same
104 | * container. Embedded views already have a node.next, but it is only set for
105 | * views in the same container. We need a way to link component views and views
106 | * across containers as well.
107 | */
108 | [NEXT]: LView|LContainer|null;
109 |
110 | /** Queries active for this view - nodes from a view are reported to those queries. */
111 | [QUERIES]: any|null;
112 |
113 | /**
114 | * Pointer to the `TViewNode` or `TElementNode` which represents the root of the view.
115 | *
116 | * If `TViewNode`, this is an embedded view of a container. We need this to be able to
117 | * efficiently find the `LViewNode` when inserting the view into an anchor.
118 | *
119 | * If `TElementNode`, this is the LView of a component.
120 | *
121 | * If null, this is the root view of an application (root component is in this view).
122 | */
123 | [T_HOST]: TViewNode|TElementNode|null;
124 |
125 | /**
126 | * When a view is destroyed, listeners need to be released and outputs need to be
127 | * unsubscribed. This context array stores both listener functions wrapped with
128 | * their context and output subscription instances for a particular view.
129 | *
130 | * These change per LView instance, so they cannot be stored on TView. Instead,
131 | * TView.cleanup saves an index to the necessary context in this array.
132 | */
133 | // TODO: flatten into LView[]
134 | [CLEANUP]: any[]|null;
135 |
136 | /**
137 | * - For dynamic views, this is the context with which to render the template (e.g.
138 | * `NgForContext`), or `{}` if not defined explicitly.
139 | * - For root view of the root component the context contains change detection data.
140 | * - For non-root components, the context is the component instance,
141 | * - For inline views, the context is null.
142 | */
143 | [CONTEXT]: {}|RootContext|null;
144 |
145 | /** An optional Module Injector to be used as fall back after Element Injectors are consulted. */
146 | readonly[INJECTOR]: any|null;
147 |
148 | /** Factory to be used for creating Renderer. */
149 | [RENDERER_FACTORY]: RendererFactory3;
150 |
151 | /** Renderer to be used for this view. */
152 | [RENDERER]: Renderer3;
153 |
154 | /** An optional custom sanitizer. */
155 | [SANITIZER]: any|null;
156 |
157 | /**
158 | * Reference to the first LView or LContainer beneath this LView in
159 | * the hierarchy.
160 | *
161 | * Necessary to store this so views can traverse through their nested views
162 | * to remove listeners and call onDestroy callbacks.
163 | */
164 | [CHILD_HEAD]: LView|LContainer|null;
165 |
166 | /**
167 | * The last LView or LContainer beneath this LView in the hierarchy.
168 | *
169 | * The tail allows us to quickly add a new state to the end of the view list
170 | * without having to propagate starting from the first child.
171 | */
172 | [CHILD_TAIL]: LView|LContainer|null;
173 |
174 | /**
175 | * View where this view's template was declared.
176 | *
177 | * Only applicable for dynamically created views. Will be null for inline/component views.
178 | *
179 | * The template for a dynamically created view may be declared in a different view than
180 | * it is inserted. We already track the "insertion view" (view where the template was
181 | * inserted) in LView[PARENT], but we also need access to the "declaration view"
182 | * (view where the template was declared). Otherwise, we wouldn't be able to call the
183 | * view's template function with the proper contexts. Context should be inherited from
184 | * the declaration view tree, not the insertion view tree.
185 | *
186 | * Example (AppComponent template):
187 | *
188 | * <-- declared here -->
189 | * <-- inserted inside this component -->
190 | *
191 | * The above is declared in the AppComponent template, but it will be passed into
192 | * SomeComp and inserted there. In this case, the declaration view would be the AppComponent,
193 | * but the insertion view would be SomeComp. When we are removing views, we would want to
194 | * traverse through the insertion view to clean up listeners. When we are calling the
195 | * template function during change detection, we need the declaration view to get inherited
196 | * context.
197 | */
198 | [DECLARATION_VIEW]: LView|null;
199 |
200 |
201 | /**
202 | * Points to the declaration component view, used to track transplanted `LView`s.
203 | *
204 | * See: `DECLARATION_VIEW` which points to the actual `LView` where it was declared, whereas
205 | * `DECLARATION_COMPONENT_VIEW` points to the component which may not be same as
206 | * `DECLARATION_VIEW`.
207 | *
208 | * Example:
209 | * ```
210 | * <#VIEW #myComp>
211 | *
212 | * ...
213 | *
214 | * #VIEW>
215 | * ```
216 | * In the above case `DECLARATION_VIEW` for `myTmpl` points to the `LView` of `ngIf` whereas
217 | * `DECLARATION_COMPONENT_VIEW` points to `LView` of the `myComp` which owns the template.
218 | *
219 | * The reason for this is that all embedded views are always check-always whereas the component
220 | * view can be check-always or on-push. When we have a transplanted view it is important to
221 | * determine if we have transplanted a view from check-always declaration to on-push insertion
222 | * point. In such a case the transplanted view needs to be added to the `LContainer` in the
223 | * declared `LView` and CD during the declared view CD (in addition to the CD at the insertion
224 | * point.) (Any transplanted views which are intra Component are of no interest because the CD
225 | * strategy of declaration and insertion will always be the same, because it is the same
226 | * component.)
227 | *
228 | * Queries already track moved views in `LView[DECLARATION_LCONTAINER]` and
229 | * `LContainer[MOVED_VIEWS]`. However the queries also track `LView`s which moved within the same
230 | * component `LView`. Transplanted views are a subset of moved views, and we use
231 | * `DECLARATION_COMPONENT_VIEW` to differentiate them. As in this example.
232 | *
233 | * Example showing intra component `LView` movement.
234 | * ```
235 | * <#VIEW #myComp>
236 | *
237 | * Content to render when condition is true.
238 | * Content to render when condition is false.
239 | * #VIEW>
240 | * ```
241 | * The `thenBlock` and `elseBlock` is moved but not transplanted.
242 | *
243 | * Example showing inter component `LView` movement (transplanted view).
244 | * ```
245 | * <#VIEW #myComp>
246 | * ...
247 | *
248 | * #VIEW>
249 | * ```
250 | * In the above example `myTmpl` is passed into a different component. If `insertion-component`
251 | * instantiates `myTmpl` and `insertion-component` is on-push then the `LContainer` needs to be
252 | * marked as containing transplanted views and those views need to be CD as part of the
253 | * declaration CD.
254 | *
255 | *
256 | * When change detection runs, it iterates over `[MOVED_VIEWS]` and CDs any child `LView`s where
257 | * the `DECLARATION_COMPONENT_VIEW` of the current component and the child `LView` does not match
258 | * (it has been transplanted across components.)
259 | *
260 | * Note: `[DECLARATION_COMPONENT_VIEW]` points to itself if the LView is a component view (the
261 | * simplest / most common case).
262 | *
263 | * see also:
264 | * - https://hackmd.io/@mhevery/rJUJsvv9H write up of the problem
265 | * - `LContainer[ACTIVE_INDEX]` for flag which marks which `LContainer` has transplanted views.
266 | * - `LContainer[TRANSPLANT_HEAD]` and `LContainer[TRANSPLANT_TAIL]` storage for transplanted
267 | * - `LView[DECLARATION_LCONTAINER]` similar problem for queries
268 | * - `LContainer[MOVED_VIEWS]` similar problem for queries
269 | */
270 | [DECLARATION_COMPONENT_VIEW]: LView;
271 |
272 | /**
273 | * A declaration point of embedded views (ones instantiated based on the content of a
274 | * ), null for other types of views.
275 | *
276 | * We need to track all embedded views created from a given declaration point so we can prepare
277 | * query matches in a proper order (query matches are ordered based on their declaration point and
278 | * _not_ the insertion point).
279 | */
280 | [DECLARATION_LCONTAINER]: LContainer|null;
281 |
282 | /**
283 | * More flags for this view. See PreOrderHookFlags for more info.
284 | */
285 | [PREORDER_HOOK_FLAGS]: PreOrderHookFlags;
286 | }
287 |
288 | /** Flags associated with an LView (saved in LView[FLAGS]) */
289 | export const enum LViewFlags {
290 | /** The state of the init phase on the first 2 bits */
291 | InitPhaseStateIncrementer = 0b00000000001,
292 | InitPhaseStateMask = 0b00000000011,
293 |
294 | /**
295 | * Whether or not the view is in creationMode.
296 | *
297 | * This must be stored in the view rather than using `data` as a marker so that
298 | * we can properly support embedded views. Otherwise, when exiting a child view
299 | * back into the parent view, `data` will be defined and `creationMode` will be
300 | * improperly reported as false.
301 | */
302 | CreationMode = 0b00000000100,
303 |
304 | /**
305 | * Whether or not this LView instance is on its first processing pass.
306 | *
307 | * An LView instance is considered to be on its "first pass" until it
308 | * has completed one creation mode run and one update mode run. At this
309 | * time, the flag is turned off.
310 | */
311 | FirstLViewPass = 0b00000001000,
312 |
313 | /** Whether this view has default change detection strategy (checks always) or onPush */
314 | CheckAlways = 0b00000010000,
315 |
316 | /**
317 | * Whether or not manual change detection is turned on for onPush components.
318 | *
319 | * This is a special mode that only marks components dirty in two cases:
320 | * 1) There has been a change to an @Input property
321 | * 2) `markDirty()` has been called manually by the user
322 | *
323 | * Note that in this mode, the firing of events does NOT mark components
324 | * dirty automatically.
325 | *
326 | * Manual mode is turned off by default for backwards compatibility, as events
327 | * automatically mark OnPush components dirty in View Engine.
328 | *
329 | * TODO: Add a public API to ChangeDetectionStrategy to turn this mode on
330 | */
331 | ManualOnPush = 0b00000100000,
332 |
333 | /** Whether or not this view is currently dirty (needing check) */
334 | Dirty = 0b000001000000,
335 |
336 | /** Whether or not this view is currently attached to change detection tree. */
337 | Attached = 0b000010000000,
338 |
339 | /** Whether or not this view is destroyed. */
340 | Destroyed = 0b000100000000,
341 |
342 | /** Whether or not this view is the root view */
343 | IsRoot = 0b001000000000,
344 |
345 | /**
346 | * Index of the current init phase on last 22 bits
347 | */
348 | IndexWithinInitPhaseIncrementer = 0b010000000000,
349 | IndexWithinInitPhaseShift = 10,
350 | IndexWithinInitPhaseReset = 0b001111111111,
351 | }
352 |
353 | /**
354 | * Possible states of the init phase:
355 | * - 00: OnInit hooks to be run.
356 | * - 01: AfterContentInit hooks to be run
357 | * - 10: AfterViewInit hooks to be run
358 | * - 11: All init hooks have been run
359 | */
360 | export const enum InitPhaseState {
361 | OnInitHooksToBeRun = 0b00,
362 | AfterContentInitHooksToBeRun = 0b01,
363 | AfterViewInitHooksToBeRun = 0b10,
364 | InitPhaseCompleted = 0b11,
365 | }
366 |
367 | /** More flags associated with an LView (saved in LView[PREORDER_HOOK_FLAGS]) */
368 | export const enum PreOrderHookFlags {
369 | /** The index of the next pre-order hook to be called in the hooks array, on the first 16
370 | bits */
371 | IndexOfTheNextPreOrderHookMaskMask = 0b01111111111111111,
372 |
373 | /**
374 | * The number of init hooks that have already been called, on the last 16 bits
375 | */
376 | NumberOfInitHooksCalledIncrementer = 0b010000000000000000,
377 | NumberOfInitHooksCalledShift = 16,
378 | NumberOfInitHooksCalledMask = 0b11111111111111110000000000000000,
379 | }
380 |
381 | /**
382 | * Explicitly marks `TView` as a specific type in `ngDevMode`
383 | *
384 | * It is useful to know conceptually what time of `TView` we are dealing with when
385 | * debugging an application (even if the runtime does not need it.) For this reason
386 | * we store this information in the `ngDevMode` `TView` and than use it for
387 | * better debugging experience.
388 | */
389 | export const enum TViewType {
390 | /**
391 | * Root `TView` is the used to bootstrap components into. It is used in conjunction with
392 | * `LView` which takes an existing DOM node not owned by Angular and wraps it in `TView`/`LView`
393 | * so that other components can be loaded into it.
394 | */
395 | Root = 0,
396 |
397 | /**
398 | * `TView` associated with a Component. This would be the `TView` directly associated with the
399 | * component view (as opposed an `Embedded` `TView` which would be a child of `Component` `TView`)
400 | */
401 | Component = 1,
402 |
403 | /**
404 | * `TView` associated with a template. Such as `*ngIf`, `` etc... A `Component`
405 | * can have zero or more `Embedede` `TView`s.
406 | */
407 | Embedded = 2,
408 | }
409 |
410 | /**
411 | * The static data for an LView (shared between all templates of a
412 | * given type).
413 | *
414 | * Stored on the `ComponentDef.tView`.
415 | */
416 | export interface TView {
417 | /**
418 | * Type of `TView` (`Root`|`Component`|`Embedded`).
419 | */
420 | type: TViewType;
421 |
422 | /**
423 | * ID for inline views to determine whether a view is the same as the previous view
424 | * in a certain position. If it's not, we know the new view needs to be inserted
425 | * and the one that exists needs to be removed (e.g. if/else statements)
426 | *
427 | * If this is -1, then this is a component view or a dynamically created view.
428 | */
429 | readonly id: number;
430 |
431 | /**
432 | * This is a blueprint used to generate LView instances for this TView. Copying this
433 | * blueprint is faster than creating a new LView from scratch.
434 | */
435 | blueprint: LView;
436 |
437 | /**
438 | * The template function used to refresh the view of dynamically created views
439 | * and components. Will be null for inline views.
440 | */
441 | template: ComponentTemplate<{}>|null;
442 |
443 | /**
444 | * A function containing query-related instructions.
445 | */
446 | viewQuery: ViewQueriesFunction<{}>|null;
447 |
448 | /**
449 | * Pointer to the host `TNode` (not part of this TView).
450 | *
451 | * If this is a `TViewNode` for an `LViewNode`, this is an embedded view of a container.
452 | * We need this pointer to be able to efficiently find this node when inserting the view
453 | * into an anchor.
454 | *
455 | * If this is a `TElementNode`, this is the view of a root component. It has exactly one
456 | * root TNode.
457 | *
458 | * If this is null, this is the view of a component that is not at root. We do not store
459 | * the host TNodes for child component views because they can potentially have several
460 | * different host TNodes, depending on where the component is being used. These host
461 | * TNodes cannot be shared (due to different indices, etc).
462 | */
463 | node: TViewNode|TElementNode|null;
464 |
465 | /** Whether or not this template has been processed in creation mode. */
466 | firstCreatePass: boolean;
467 |
468 | /**
469 | * Whether or not this template has been processed in update mode (e.g. change detected)
470 | *
471 | * `firstUpdatePass` is used by styling to set up `TData` to contain metadata about the styling
472 | * instructions. (Mainly to build up a linked list of styling priority order.)
473 | *
474 | * Typically this function gets cleared after first execution. If exception is thrown then this
475 | * flag can remain turned un until there is first successful (no exception) pass. This means that
476 | * individual styling instructions keep track of if they have already been added to the linked
477 | * list to prevent double adding.
478 | */
479 | firstUpdatePass: boolean;
480 |
481 | /** Static data equivalent of LView.data[]. Contains TNodes, PipeDefInternal or TI18n. */
482 | data: TData;
483 |
484 | /**
485 | * The binding start index is the index at which the data array
486 | * starts to store bindings only. Saving this value ensures that we
487 | * will begin reading bindings at the correct point in the array when
488 | * we are in update mode.
489 | *
490 | * -1 means that it has not been initialized.
491 | */
492 | bindingStartIndex: number;
493 |
494 | /**
495 | * The index where the "expando" section of `LView` begins. The expando
496 | * section contains injectors, directive instances, and host binding values.
497 | * Unlike the "decls" and "vars" sections of `LView`, the length of this
498 | * section cannot be calculated at compile-time because directives are matched
499 | * at runtime to preserve locality.
500 | *
501 | * We store this start index so we know where to start checking host bindings
502 | * in `setHostBindings`.
503 | */
504 | expandoStartIndex: number;
505 |
506 | /**
507 | * Whether or not there are any static view queries tracked on this view.
508 | *
509 | * We store this so we know whether or not we should do a view query
510 | * refresh after creation mode to collect static query results.
511 | */
512 | staticViewQueries: boolean;
513 |
514 | /**
515 | * Whether or not there are any static content queries tracked on this view.
516 | *
517 | * We store this so we know whether or not we should do a content query
518 | * refresh after creation mode to collect static query results.
519 | */
520 | staticContentQueries: boolean;
521 |
522 | /**
523 | * A reference to the first child node located in the view.
524 | */
525 | firstChild: TNode|null;
526 |
527 | /**
528 | * Set of instructions used to process host bindings efficiently.
529 | *
530 | * See VIEW_DATA.md for more information.
531 | */
532 | // TODO(misko): `expandoInstructions` should be renamed to `hostBindingsInstructions` since they
533 | // keep track of `hostBindings` which need to be executed.
534 | expandoInstructions: any|null;
535 |
536 | /**
537 | * Full registry of directives and components that may be found in this view.
538 | *
539 | * It's necessary to keep a copy of the full def list on the TView so it's possible
540 | * to render template functions without a host component.
541 | */
542 | directiveRegistry: DirectiveDefList|null;
543 |
544 | /**
545 | * Full registry of pipes that may be found in this view.
546 | *
547 | * The property is either an array of `PipeDefs`s or a function which returns the array of
548 | * `PipeDefs`s. The function is necessary to be able to support forward declarations.
549 | *
550 | * It's necessary to keep a copy of the full def list on the TView so it's possible
551 | * to render template functions without a host component.
552 | */
553 | pipeRegistry: PipeDefList|null;
554 |
555 | /**
556 | * Array of ngOnInit, ngOnChanges and ngDoCheck hooks that should be executed for this view in
557 | * creation mode.
558 | *
559 | * Even indices: Directive index
560 | * Odd indices: Hook function
561 | */
562 | preOrderHooks: HookData|null;
563 |
564 | /**
565 | * Array of ngOnChanges and ngDoCheck hooks that should be executed for this view in update mode.
566 | *
567 | * Even indices: Directive index
568 | * Odd indices: Hook function
569 | */
570 | preOrderCheckHooks: HookData|null;
571 |
572 | /**
573 | * Array of ngAfterContentInit and ngAfterContentChecked hooks that should be executed
574 | * for this view in creation mode.
575 | *
576 | * Even indices: Directive index
577 | * Odd indices: Hook function
578 | */
579 | contentHooks: HookData|null;
580 |
581 | /**
582 | * Array of ngAfterContentChecked hooks that should be executed for this view in update
583 | * mode.
584 | *
585 | * Even indices: Directive index
586 | * Odd indices: Hook function
587 | */
588 | contentCheckHooks: HookData|null;
589 |
590 | /**
591 | * Array of ngAfterViewInit and ngAfterViewChecked hooks that should be executed for
592 | * this view in creation mode.
593 | *
594 | * Even indices: Directive index
595 | * Odd indices: Hook function
596 | */
597 | viewHooks: HookData|null;
598 |
599 | /**
600 | * Array of ngAfterViewChecked hooks that should be executed for this view in
601 | * update mode.
602 | *
603 | * Even indices: Directive index
604 | * Odd indices: Hook function
605 | */
606 | viewCheckHooks: HookData|null;
607 |
608 | /**
609 | * Array of ngOnDestroy hooks that should be executed when this view is destroyed.
610 | *
611 | * Even indices: Directive index
612 | * Odd indices: Hook function
613 | */
614 | destroyHooks: HookData|null;
615 |
616 | /**
617 | * When a view is destroyed, listeners need to be released and outputs need to be
618 | * unsubscribed. This cleanup array stores both listener data (in chunks of 4)
619 | * and output data (in chunks of 2) for a particular view. Combining the arrays
620 | * saves on memory (70 bytes per array) and on a few bytes of code size (for two
621 | * separate for loops).
622 | *
623 | * If it's a native DOM listener or output subscription being stored:
624 | * 1st index is: event name `name = tView.cleanup[i+0]`
625 | * 2nd index is: index of native element or a function that retrieves global target (window,
626 | * document or body) reference based on the native element:
627 | * `typeof idxOrTargetGetter === 'function'`: global target getter function
628 | * `typeof idxOrTargetGetter === 'number'`: index of native element
629 | *
630 | * 3rd index is: index of listener function `listener = lView[CLEANUP][tView.cleanup[i+2]]`
631 | * 4th index is: `useCaptureOrIndx = tView.cleanup[i+3]`
632 | * `typeof useCaptureOrIndx == 'boolean' : useCapture boolean
633 | * `typeof useCaptureOrIndx == 'number':
634 | * `useCaptureOrIndx >= 0` `removeListener = LView[CLEANUP][useCaptureOrIndx]`
635 | * `useCaptureOrIndx < 0` `subscription = LView[CLEANUP][-useCaptureOrIndx]`
636 | *
637 | * If it's an output subscription or query list destroy hook:
638 | * 1st index is: output unsubscribe function / query list destroy function
639 | * 2nd index is: index of function context in LView.cleanupInstances[]
640 | * `tView.cleanup[i+0].call(lView[CLEANUP][tView.cleanup[i+1]])`
641 | */
642 | cleanup: any[]|null;
643 |
644 | /**
645 | * A list of element indices for child components that will need to be
646 | * refreshed when the current view has finished its check. These indices have
647 | * already been adjusted for the HEADER_OFFSET.
648 | *
649 | */
650 | components: number[]|null;
651 |
652 | /**
653 | * A collection of queries tracked in a given view.
654 | */
655 | queries: any|null;
656 |
657 | /**
658 | * An array of indices pointing to directives with content queries alongside with the
659 | * corresponding
660 | * query index. Each entry in this array is a tuple of:
661 | * - index of the first content query index declared by a given directive;
662 | * - index of a directive.
663 | *
664 | * We are storing those indexes so we can refresh content queries as part of a view refresh
665 | * process.
666 | */
667 | contentQueries: number[]|null;
668 |
669 | /**
670 | * Set of schemas that declare elements to be allowed inside the view.
671 | */
672 | schemas: SchemaMetadata[]|null;
673 |
674 | /**
675 | * Array of constants for the view. Includes attribute arrays, local definition arrays etc.
676 | * Used for directive matching, attribute bindings, local definitions and more.
677 | */
678 | consts: TConstants|null;
679 | }
680 |
681 | export const enum RootContextFlags {Empty = 0b00, DetectChanges = 0b01, FlushPlayers = 0b10}
682 |
683 |
684 | /**
685 | * RootContext contains information which is shared for all components which
686 | * were bootstrapped with {@link renderComponent}.
687 | */
688 | export interface RootContext {
689 | /**
690 | * A function used for scheduling change detection in the future. Usually
691 | * this is `requestAnimationFrame`.
692 | */
693 | scheduler: (workFn: () => void) => void;
694 |
695 | /**
696 | * A promise which is resolved when all components are considered clean (not dirty).
697 | *
698 | * This promise is overwritten every time a first call to {@link markDirty} is invoked.
699 | */
700 | clean: Promise;
701 |
702 | /**
703 | * RootComponents - The components that were instantiated by the call to
704 | * {@link renderComponent}.
705 | */
706 | components: {}[];
707 |
708 | /**
709 | * The player flushing handler to kick off all animations
710 | */
711 | playerHandler: PlayerHandler|null;
712 |
713 | /**
714 | * What render-related operations to run once a scheduler has been set
715 | */
716 | flags: RootContextFlags;
717 | }
718 |
719 | /**
720 | * Array of hooks that should be executed for a view and their directive indices.
721 | *
722 | * For each node of the view, the following data is stored:
723 | * 1) Node index (optional)
724 | * 2) A series of number/function pairs where:
725 | * - even indices are directive indices
726 | * - odd indices are hook functions
727 | *
728 | * Special cases:
729 | * - a negative directive index flags an init hook (ngOnInit, ngAfterContentInit, ngAfterViewInit)
730 | */
731 | export type HookData = (number | (() => void))[];
732 |
733 | /**
734 | * Static data that corresponds to the instance-specific data array on an LView.
735 | *
736 | * Each node's static data is stored in tData at the same index that it's stored
737 | * in the data array. Any nodes that do not have static data store a null value in
738 | * tData to avoid a sparse array.
739 | *
740 | * Each pipe's definition is stored here at the same index as its pipe instance in
741 | * the data array.
742 | *
743 | * Each host property's name is stored here at the same index as its value in the
744 | * data array.
745 | *
746 | * Each property binding name is stored here at the same index as its value in
747 | * the data array. If the binding is an interpolation, the static string values
748 | * are stored parallel to the dynamic values. Example:
749 | *
750 | * id="prefix {{ v0 }} a {{ v1 }} b {{ v2 }} suffix"
751 | *
752 | * LView | TView.data
753 | *------------------------
754 | * v0 value | 'a'
755 | * v1 value | 'b'
756 | * v2 value | id � prefix � suffix
757 | *
758 | * Injector bloom filters are also stored here.
759 | */
760 | export type TData =
761 | (TNode | PipeDef| DirectiveDef| ComponentDef| number | Type| InjectionToken| null | string)[];
762 |
763 | // Note: This hack is necessary so we don't erroneously get a circular dependency
764 | // failure based on types.
765 | export const unusedValueExportToPlacateAjd = 1;
766 |
--------------------------------------------------------------------------------