refactor(ivy): add type and hooks to directive def (#21650)
PR Close #21650
This commit is contained in:

committed by
Misko Hevery

parent
97b928053d
commit
98174758ad
@ -13,8 +13,9 @@ import {ComponentRef as viewEngine_ComponentRef} from '../linker/component_facto
|
||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef} from '../linker/view_ref';
|
||||
|
||||
import {assertNotNull} from './assert';
|
||||
|
||||
import {NG_HOST_SYMBOL, createError, createLView, directiveCreate, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
|
||||
import {ComponentDef, ComponentType, TypedComponentDef} from './interfaces/definition';
|
||||
import {ComponentDef, ComponentType} from './interfaces/definition';
|
||||
import {LElementNode} from './interfaces/node';
|
||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {notImplemented, stringify} from './util';
|
||||
@ -166,7 +167,7 @@ export const NULL_INJECTOR: Injector = {
|
||||
export function renderComponent<T>(
|
||||
componentType: ComponentType<T>, opts: CreateComponentOptions = {}): T {
|
||||
const rendererFactory = opts.rendererFactory || domRendererFactory3;
|
||||
const componentDef = componentType.ngComponentDef as TypedComponentDef<T>;
|
||||
const componentDef = componentType.ngComponentDef as ComponentDef<T>;
|
||||
if (componentDef.type != componentType) componentDef.type = componentType;
|
||||
let component: T;
|
||||
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
|
||||
|
@ -14,7 +14,7 @@ import {resolveRendererType2} from '../view/util';
|
||||
|
||||
import {diPublic} from './di';
|
||||
import {componentRefresh} from './instructions';
|
||||
import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs, TypedDirectiveDef} from './interfaces/definition';
|
||||
import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs, LifecycleHooksMap} from './interfaces/definition';
|
||||
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ import {ComponentDef, ComponentDefArgs, DirectiveDef, DirectiveDefArgs, TypedDir
|
||||
*/
|
||||
export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): ComponentDef<T> {
|
||||
const def = <ComponentDef<any>>{
|
||||
type: componentDefinition.type,
|
||||
diPublic: null,
|
||||
n: componentDefinition.factory,
|
||||
tag: (componentDefinition as ComponentDefArgs<T>).tag || null !,
|
||||
@ -50,6 +51,7 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
|
||||
methods: invertObject(componentDefinition.methods),
|
||||
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
|
||||
exportAs: componentDefinition.exportAs,
|
||||
lifecycleHooks: getLifecyleHooksMap<T>(componentDefinition.type)
|
||||
};
|
||||
const feature = componentDefinition.features;
|
||||
feature && feature.forEach((fn) => fn(def));
|
||||
@ -65,7 +67,7 @@ type OnChangesExpando = OnChanges & {
|
||||
};
|
||||
|
||||
export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<any>) => void {
|
||||
return function(definition: DirectiveDef<any>): void {
|
||||
return function (definition: DirectiveDef<any>): void {
|
||||
const inputs = definition.inputs;
|
||||
const proto = type.prototype;
|
||||
// Place where we will store SimpleChanges if there is a change
|
||||
@ -80,11 +82,11 @@ export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<
|
||||
|
||||
// create a getter and setter for property
|
||||
Object.defineProperty(proto, minKey, {
|
||||
get: function(this: OnChangesExpando) {
|
||||
get: function (this: OnChangesExpando) {
|
||||
return (existingDesc && existingDesc.get) ? existingDesc.get.call(this) :
|
||||
this[privateMinKey];
|
||||
this[privateMinKey];
|
||||
},
|
||||
set: function(this: OnChangesExpando, value: any) {
|
||||
set: function (this: OnChangesExpando, value: any) {
|
||||
let simpleChanges = this[PRIVATE_PREFIX];
|
||||
let isFirstChange = simpleChanges === undefined;
|
||||
if (simpleChanges == null) {
|
||||
@ -92,12 +94,12 @@ export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<
|
||||
}
|
||||
simpleChanges[pubKey] = new SimpleChange(this[privateMinKey], value, isFirstChange);
|
||||
(existingDesc && existingDesc.set) ? existingDesc.set.call(this, value) :
|
||||
this[privateMinKey] = value;
|
||||
this[privateMinKey] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
proto.ngDoCheck = (function(delegateDoCheck) {
|
||||
return function(this: OnChangesExpando) {
|
||||
proto.ngDoCheck = (function (delegateDoCheck) {
|
||||
return function (this: OnChangesExpando) {
|
||||
let simpleChanges = this[PRIVATE_PREFIX];
|
||||
if (simpleChanges != null) {
|
||||
this.ngOnChanges(simpleChanges);
|
||||
@ -109,6 +111,25 @@ export function NgOnChangesFeature<T>(type: Type<T>): (definition: DirectiveDef<
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the component type and returns a formatted map of lifecycle hooks for that
|
||||
* component.
|
||||
*
|
||||
* @param type The component type
|
||||
*/
|
||||
function getLifecyleHooksMap<T>(type: Type<T>): LifecycleHooksMap {
|
||||
return {
|
||||
onInit: type.prototype.ngOnInit || null,
|
||||
doCheck: type.prototype.ngDoCheck || null,
|
||||
afterContentInit: type.prototype.ngAfterContentInit || null,
|
||||
afterContentChecked: type.prototype.ngAfterContentChecked || null,
|
||||
afterViewInit: type.prototype.ngAfterViewInit || null,
|
||||
afterViewChecked: type.prototype.ngAfterViewChecked || null,
|
||||
onDestroy: type.prototype.ngOnDestroy || null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function PublicFeature<T>(definition: DirectiveDef<T>) {
|
||||
definition.diPublic = diPublic;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import {Type} from '../type';
|
||||
|
||||
import {assertLessThan} from './assert';
|
||||
import {assertPreviousIsParent, getPreviousOrParentNode, getRenderer, renderEmbeddedTemplate} from './instructions';
|
||||
import {ComponentTemplate, DirectiveDef, TypedDirectiveDef} from './interfaces/definition';
|
||||
import {ComponentTemplate, DirectiveDef} from './interfaces/definition';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode} from './interfaces/node';
|
||||
import {QueryReadType} from './interfaces/query';
|
||||
@ -158,7 +158,7 @@ function createInjectionError(text: string, token: any) {
|
||||
* @param di The node injector in which a directive will be added
|
||||
* @param def The definition of the directive to be made public
|
||||
*/
|
||||
export function diPublicInInjector(di: LInjector, def: TypedDirectiveDef<any>): void {
|
||||
export function diPublicInInjector(di: LInjector, def: DirectiveDef<any>): void {
|
||||
bloomAdd(di, def.type);
|
||||
}
|
||||
|
||||
@ -291,7 +291,7 @@ export function getOrCreateInjectable<T>(
|
||||
for (let i = start, ii = start + size; i < ii; i++) {
|
||||
// Get the definition for the directive at this index and, if it is injectable (diPublic),
|
||||
// and matches the given token, return the directive instance.
|
||||
const directiveDef = tData[i] as TypedDirectiveDef<any>;
|
||||
const directiveDef = tData[i] as DirectiveDef<any>;
|
||||
if (directiveDef.diPublic && directiveDef.type == token) {
|
||||
return node.view.data[i];
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextN
|
||||
import {assertNodeType, assertNodeOfPossibleTypes} from './node_assert';
|
||||
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
|
||||
import {isNodeMatchingSelector} from './node_selector_matcher';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, TypedDirectiveDef, TypedComponentDef} from './interfaces/definition';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType} from './interfaces/definition';
|
||||
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer';
|
||||
import {isDifferent, stringify} from './util';
|
||||
|
||||
@ -447,8 +447,6 @@ export function elementStart(
|
||||
if (hostComponentDef) {
|
||||
// TODO(mhevery): This assumes that the directives come in correct order, which
|
||||
// is not guaranteed. Must be refactored to take it into account.
|
||||
(hostComponentDef as TypedComponentDef<any>).type =
|
||||
nameOrComponentType as ComponentType<any>;
|
||||
directiveCreate(++index, hostComponentDef.n(), hostComponentDef, queryName);
|
||||
}
|
||||
hack_declareDirectives(index, directiveTypes, localRefs);
|
||||
@ -476,7 +474,6 @@ function hack_declareDirectives(
|
||||
// TODO(misko): refactor this to store the `DirectiveDef` in `TView.data`.
|
||||
const directiveType = directiveTypes[i];
|
||||
const directiveDef = directiveType.ngDirectiveDef;
|
||||
(directiveDef as TypedDirectiveDef<any>).type = directiveType;
|
||||
directiveCreate(
|
||||
++index, directiveDef.n(), directiveDef, hack_findQueryName(directiveDef, localRefs));
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ export const enum DirectiveDefFlags {ContentQuery = 0b10}
|
||||
* `DirectiveDef` is a compiled version of the Directive used by the renderer instructions.
|
||||
*/
|
||||
export interface DirectiveDef<T> {
|
||||
/** Token representing the directive. Used by DI. */
|
||||
type: Type<T>;
|
||||
|
||||
/** Function that makes a directive public to the DI system. */
|
||||
diPublic: ((def: DirectiveDef<any>) => void)|null;
|
||||
|
||||
@ -85,6 +88,9 @@ export interface DirectiveDef<T> {
|
||||
// (for backwards compatibility). Child template processing thus needs to be
|
||||
// delayed until all inputs and host bindings in a view have been checked.
|
||||
h(directiveIndex: number, elementIndex: number): void;
|
||||
|
||||
/* A map of the lifecycle hooks defined on this directive (key: name, value: fn) */
|
||||
lifecycleHooks: LifecycleHooksMap;
|
||||
}
|
||||
|
||||
export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
@ -122,17 +128,19 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
readonly rendererType: RendererType2|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private: do not export
|
||||
*/
|
||||
export interface TypedDirectiveDef<T> extends DirectiveDef<T> { type: DirectiveType<T>; }
|
||||
|
||||
/**
|
||||
* Private: do not export
|
||||
*/
|
||||
export interface TypedComponentDef<T> extends ComponentDef<T> { type: ComponentType<T>; }
|
||||
/* A map of the lifecycle hooks defined on a directive (key: name, value: fn) */
|
||||
export interface LifecycleHooksMap {
|
||||
onInit: () => void | null;
|
||||
doCheck: () => void | null;
|
||||
afterContentInit: () => void | null;
|
||||
afterContentChecked: () => void | null;
|
||||
afterViewInit: () => void | null;
|
||||
afterViewChecked: () => void | null;
|
||||
onDestroy: () => void | null;
|
||||
}
|
||||
|
||||
export interface DirectiveDefArgs<T> {
|
||||
type: Type<T>;
|
||||
factory: () => T;
|
||||
refresh?: (directiveIndex: number, elementIndex: number) => void;
|
||||
inputs?: {[P in keyof T]?: string};
|
||||
|
@ -18,7 +18,7 @@ import {Type} from '../type';
|
||||
import {assertNotNull} from './assert';
|
||||
import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
|
||||
import {assertPreviousIsParent, getCurrentQuery} from './instructions';
|
||||
import {DirectiveDef, TypedDirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
||||
import {DirectiveDef, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
|
||||
import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
||||
import {LContainerNode, LElementNode, LNode, LNodeFlags, LViewNode, TNode, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
||||
import {LQuery, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
||||
@ -159,7 +159,7 @@ function geIdxOfMatchingDirective(node: LNode, type: Type<any>): number|null {
|
||||
for (let i = flags >> LNodeFlags.INDX_SHIFT,
|
||||
ii = i + ((flags & LNodeFlags.SIZE_MASK) >> LNodeFlags.SIZE_SHIFT);
|
||||
i < ii; i++) {
|
||||
const def = tData[i] as TypedDirectiveDef<any>;
|
||||
const def = tData[i] as DirectiveDef<any>;
|
||||
if (def.diPublic && def.type === type) {
|
||||
return i;
|
||||
}
|
||||
|
Reference in New Issue
Block a user