refactor(ivy): remove pipe references from the template (#23032)
PR Close #23032
This commit is contained in:

committed by
Alex Rickabaugh

parent
5a86f7144f
commit
e2e80ec61c
@ -133,8 +133,9 @@ export function renderComponent<T>(
|
||||
clean: CLEAN_PROMISE,
|
||||
};
|
||||
const rootView = createLView(
|
||||
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), createTView(null),
|
||||
null, rootContext, componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
|
||||
-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType),
|
||||
createTView(null, null), null, rootContext,
|
||||
componentDef.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways);
|
||||
|
||||
const oldView = enterView(rootView, null !);
|
||||
let elementNode: LElementNode;
|
||||
|
@ -16,7 +16,7 @@ import {Type} from '../type';
|
||||
import {resolveRendererType2} from '../view/util';
|
||||
|
||||
import {diPublic} from './di';
|
||||
import {ComponentDef, ComponentDefFeature, ComponentTemplate, DirectiveDef, DirectiveDefFeature, DirectiveDefListOrFactory, PipeDef} from './interfaces/definition';
|
||||
import {ComponentDef, ComponentDefFeature, ComponentTemplate, DirectiveDef, DirectiveDefFeature, DirectiveDefListOrFactory, PipeDef, PipeDefListOrFactory} from './interfaces/definition';
|
||||
import {CssSelector} from './interfaces/projection';
|
||||
|
||||
|
||||
@ -154,6 +154,14 @@ export function defineComponent<T>(componentDefinition: {
|
||||
* `DirectiveDef`s. The function is necessary to be able to support forward declarations.
|
||||
*/
|
||||
directiveDefs?: DirectiveDefListOrFactory | null;
|
||||
|
||||
/**
|
||||
* Registry of pipes that may be found in this component's view.
|
||||
*
|
||||
* The property is either an array of `PipeDefs`s or a function which returns the array of
|
||||
* `PipeDefs`s. The function is necessary to be able to support forward declarations.
|
||||
*/
|
||||
pipeDefs?: PipeDefListOrFactory | null;
|
||||
}): ComponentDef<T> {
|
||||
const type = componentDefinition.type;
|
||||
const def = <ComponentDef<any>>{
|
||||
@ -176,6 +184,7 @@ export function defineComponent<T>(componentDefinition: {
|
||||
onDestroy: type.prototype.ngOnDestroy || null,
|
||||
onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
|
||||
directiveDefs: componentDefinition.directiveDefs || null,
|
||||
pipeDefs: componentDefinition.pipeDefs || null,
|
||||
selector: componentDefinition.selector
|
||||
};
|
||||
const feature = componentDefinition.features;
|
||||
@ -380,15 +389,25 @@ export const defineDirective = defineComponent as any as<T>(directiveDefinition:
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @param type Pipe class reference. Needed to extract pipe lifecycle hooks.
|
||||
* @param factory A factory for creating a pipe instance.
|
||||
* @param pure Whether the pipe is pure.
|
||||
* @param pipeDef Pipe definition generated by the compiler
|
||||
*/
|
||||
export function definePipe<T>(
|
||||
{type, factory, pure}: {type: Type<T>, factory: () => T, pure?: boolean}): PipeDef<T> {
|
||||
export function definePipe<T>(pipeDef: {
|
||||
/** Name of the pipe. Used for matching pipes in template to pipe defs. */
|
||||
name: string,
|
||||
|
||||
/** Pipe class reference. Needed to extract pipe lifecycle hooks. */
|
||||
type: Type<T>,
|
||||
|
||||
/** A factory for creating a pipe instance. */
|
||||
factory: () => T,
|
||||
|
||||
/** Whether the pipe is pure. */
|
||||
pure?: boolean
|
||||
}): PipeDef<T> {
|
||||
return <PipeDef<T>>{
|
||||
n: factory,
|
||||
pure: pure !== false,
|
||||
onDestroy: type.prototype.ngOnDestroy || null
|
||||
name: pipeDef.name,
|
||||
n: pipeDef.factory,
|
||||
pure: pipeDef.pure !== false,
|
||||
onDestroy: pipeDef.type.prototype.ngOnDestroy || null
|
||||
};
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import {LContainerNode, LElementNode, LNode, LNodeType, TNodeFlags, LProjectionN
|
||||
import {assertNodeType} from './node_assert';
|
||||
import {appendChild, insertChild, insertView, appendProjectedNode, removeView, canInsertNativeNode} from './node_manipulation';
|
||||
import {isNodeMatchingSelector, matchingSelectorIndex} from './node_selector_matcher';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, DirectiveType} from './interfaces/definition';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, DirectiveType, PipeDef, PipeDefListOrFactory} from './interfaces/definition';
|
||||
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {isDifferent, stringify} from './util';
|
||||
import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
|
||||
@ -400,20 +400,22 @@ function resetApplicationState() {
|
||||
* @param context to pass into the template.
|
||||
* @param providedRendererFactory renderer factory to use
|
||||
* @param host The host element node to use
|
||||
* @param directiveRegistry Any directive defs that should be used to match nodes to directives
|
||||
* @param defs Any directive or pipe defs that should be used for matching
|
||||
*/
|
||||
export function renderTemplate<T>(
|
||||
hostNode: RElement, template: ComponentTemplate<T>, context: T,
|
||||
providedRendererFactory: RendererFactory3, host: LElementNode | null,
|
||||
directiveRegistry: DirectiveDefListOrFactory | null = null): LElementNode {
|
||||
directives?: DirectiveDefListOrFactory | null,
|
||||
pipes?: PipeDefListOrFactory | null): LElementNode {
|
||||
if (host == null) {
|
||||
resetApplicationState();
|
||||
rendererFactory = providedRendererFactory;
|
||||
const tView = getOrCreateTView(template, directives || null, pipes || null);
|
||||
host = createLNode(
|
||||
null, LNodeType.Element, hostNode,
|
||||
createLView(
|
||||
-1, providedRendererFactory.createRenderer(null, null),
|
||||
getOrCreateTView(template, directiveRegistry), null, {}, LViewFlags.CheckAlways));
|
||||
-1, providedRendererFactory.createRenderer(null, null), tView, null, {},
|
||||
LViewFlags.CheckAlways));
|
||||
}
|
||||
const hostView = host.data !;
|
||||
ngDevMode && assertNotNull(hostView, 'Host node should have an LView defined in host.data.');
|
||||
@ -432,9 +434,11 @@ export function renderEmbeddedTemplate<T>(
|
||||
let cm: boolean = false;
|
||||
if (viewNode == null) {
|
||||
// TODO: revisit setting currentView when re-writing view containers
|
||||
const directives = currentView && currentView.tView.directiveRegistry;
|
||||
const pipes = currentView && currentView.tView.pipeRegistry;
|
||||
|
||||
const view = createLView(
|
||||
-1, renderer, createTView(currentView && currentView.tView.directiveRegistry), template,
|
||||
context, LViewFlags.CheckAlways);
|
||||
-1, renderer, createTView(directives, pipes), template, context, LViewFlags.CheckAlways);
|
||||
viewNode = createLNode(null, LNodeType.View, null, view);
|
||||
cm = true;
|
||||
}
|
||||
@ -655,15 +659,20 @@ function saveResolvedLocalsInData(): void {
|
||||
* if it doesn't already exist.
|
||||
*
|
||||
* @param template The template from which to get static data
|
||||
* @param directives Directive defs that should be saved on TView
|
||||
* @param pipes Pipe defs that should be saved on TView
|
||||
* @returns TView
|
||||
*/
|
||||
function getOrCreateTView(
|
||||
template: ComponentTemplate<any>, defs: DirectiveDefListOrFactory | null): TView {
|
||||
return template.ngPrivateData || (template.ngPrivateData = createTView(defs) as never);
|
||||
template: ComponentTemplate<any>, directives: DirectiveDefListOrFactory | null,
|
||||
pipes: PipeDefListOrFactory | null): TView {
|
||||
return template.ngPrivateData ||
|
||||
(template.ngPrivateData = createTView(directives, pipes) as never);
|
||||
}
|
||||
|
||||
/** Creates a TView instance */
|
||||
export function createTView(defs: DirectiveDefListOrFactory | null): TView {
|
||||
export function createTView(
|
||||
defs: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null): TView {
|
||||
return {
|
||||
data: [],
|
||||
directives: null,
|
||||
@ -678,7 +687,8 @@ export function createTView(defs: DirectiveDefListOrFactory | null): TView {
|
||||
pipeDestroyHooks: null,
|
||||
hostBindings: null,
|
||||
components: null,
|
||||
directiveRegistry: typeof defs === 'function' ? defs() : defs
|
||||
directiveRegistry: typeof defs === 'function' ? defs() : defs,
|
||||
pipeRegistry: typeof pipes === 'function' ? pipes() : pipes
|
||||
};
|
||||
}
|
||||
|
||||
@ -740,7 +750,7 @@ export function hostElement(
|
||||
const node = createLNode(
|
||||
0, LNodeType.Element, rNode,
|
||||
createLView(
|
||||
-1, renderer, getOrCreateTView(def.template, def.directiveDefs), null, null,
|
||||
-1, renderer, getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs), null, null,
|
||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways));
|
||||
|
||||
if (firstTemplatePass) {
|
||||
@ -1170,7 +1180,7 @@ export function directiveCreate<T>(
|
||||
|
||||
function addComponentLogic<T>(
|
||||
index: number, elementIndex: number, instance: T, def: ComponentDef<any>): void {
|
||||
const tView = getOrCreateTView(def.template, def.directiveDefs);
|
||||
const tView = getOrCreateTView(def.template, def.directiveDefs, def.pipeDefs);
|
||||
|
||||
// Only component views should be added to the view tree directly. Embedded views are
|
||||
// accessed through their containers because they may be removed / re-added later.
|
||||
@ -1476,7 +1486,8 @@ function getOrCreateEmbeddedTView(viewIndex: number, parent: LContainerNode): TV
|
||||
ngDevMode && assertNodeType(parent, LNodeType.Container);
|
||||
const tContainer = (parent !.tNode as TContainerNode).data;
|
||||
if (viewIndex >= tContainer.length || tContainer[viewIndex] == null) {
|
||||
tContainer[viewIndex] = createTView(currentView.tView.directiveRegistry);
|
||||
const tView = currentView.tView;
|
||||
tContainer[viewIndex] = createTView(tView.directiveRegistry, tView.pipeRegistry);
|
||||
}
|
||||
return tContainer[viewIndex];
|
||||
}
|
||||
|
@ -161,6 +161,14 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
* `DirectiveDef`s. The function is necessary to be able to support forward declarations.
|
||||
*/
|
||||
directiveDefs: DirectiveDefListOrFactory|null;
|
||||
|
||||
/**
|
||||
* Registry of pipes that may be found in this view.
|
||||
*
|
||||
* The property is either an array of `PipeDefs`s or a function which returns the array of
|
||||
* `PipeDefs`s. The function is necessary to be able to support forward declarations.
|
||||
*/
|
||||
pipeDefs: PipeDefListOrFactory|null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,6 +184,13 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
* See: {@link definePipe}
|
||||
*/
|
||||
export interface PipeDef<T> {
|
||||
/**
|
||||
* Pipe name.
|
||||
*
|
||||
* Used to resolve pipe in templates.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* factory function used to create a new directive instance.
|
||||
*
|
||||
@ -208,6 +223,15 @@ export type DirectiveDefListOrFactory = (() => DirectiveDefList) | DirectiveDefL
|
||||
|
||||
export type DirectiveDefList = (DirectiveDef<any>| ComponentDef<any>)[];
|
||||
|
||||
/**
|
||||
* Type used for PipeDefs on component definition.
|
||||
*
|
||||
* The function is necessary to be able to support forward declarations.
|
||||
*/
|
||||
export type PipeDefListOrFactory = (() => PipeDefList) | PipeDefList;
|
||||
|
||||
export type PipeDefList = PipeDef<any>[];
|
||||
|
||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||
// failure based on types.
|
||||
export const unusedValueExportToPlacateAjd = 1;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {LContainer} from './container';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, PipeDef} from './definition';
|
||||
import {ComponentTemplate, DirectiveDefList, PipeDef, PipeDefList} from './definition';
|
||||
import {LElementNode, LViewNode, TNode} from './node';
|
||||
import {LQueries} from './query';
|
||||
import {Renderer3} from './renderer';
|
||||
@ -245,6 +245,17 @@ export interface TView {
|
||||
*/
|
||||
directiveRegistry: DirectiveDefList|null;
|
||||
|
||||
/**
|
||||
* Full registry of pipes that may be found in this view.
|
||||
*
|
||||
* The property is either an array of `PipeDefs`s or a function which returns the array of
|
||||
* `PipeDefs`s. The function is necessary to be able to support forward declarations.
|
||||
*
|
||||
* It's necessary to keep a copy of the full def list on the TView so it's possible
|
||||
* to render template functions without a host component.
|
||||
*/
|
||||
pipeRegistry: PipeDefList|null;
|
||||
|
||||
/**
|
||||
* Array of ngOnInit and ngDoCheck hooks that should be executed for this view in
|
||||
* creation mode.
|
||||
|
@ -9,10 +9,9 @@
|
||||
import {PipeTransform} from '../change_detection/pipe_transform';
|
||||
|
||||
import {getTView, load, store} from './instructions';
|
||||
import {PipeDef} from './interfaces/definition';
|
||||
import {PipeDef, PipeDefList} from './interfaces/definition';
|
||||
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunctionV} from './pure_function';
|
||||
|
||||
|
||||
/**
|
||||
* Create a pipe.
|
||||
*
|
||||
@ -21,19 +20,45 @@ import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction
|
||||
* @param firstInstance (optional) The first instance of the pipe that can be reused for pure pipes.
|
||||
* @returns T the instance of the pipe.
|
||||
*/
|
||||
export function pipe<T>(index: number, pipeDef: PipeDef<T>, firstInstance?: T): T {
|
||||
export function pipe(index: number, pipeName: string, firstInstance?: any): any {
|
||||
const tView = getTView();
|
||||
let pipeDef: PipeDef<any>;
|
||||
|
||||
if (tView.firstTemplatePass) {
|
||||
pipeDef = getPipeDef(pipeName, tView.pipeRegistry);
|
||||
tView.data[index] = pipeDef;
|
||||
if (pipeDef.onDestroy) {
|
||||
(tView.pipeDestroyHooks || (tView.pipeDestroyHooks = [])).push(index, pipeDef.onDestroy);
|
||||
}
|
||||
} else {
|
||||
pipeDef = tView.data[index] as PipeDef<any>;
|
||||
}
|
||||
|
||||
const pipeInstance = pipeDef.pure && firstInstance ? firstInstance : pipeDef.n();
|
||||
store(index, pipeInstance);
|
||||
return pipeInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the pipe registry for a pipe with the given name. If one is found,
|
||||
* returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved.
|
||||
*
|
||||
* @param name Name of pipe to resolve
|
||||
* @param registry Full list of available pipes
|
||||
* @returns Matching PipeDef
|
||||
*/
|
||||
function getPipeDef(name: string, registry: PipeDefList | null): PipeDef<any> {
|
||||
if (registry) {
|
||||
for (let i = 0; i < registry.length; i++) {
|
||||
const pipeDef = registry[i];
|
||||
if (name === pipeDef.name) {
|
||||
return pipeDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error(`Pipe with name '${name}' not found!`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a pipe with 1 arguments.
|
||||
*
|
||||
|
Reference in New Issue
Block a user