@ -9,10 +9,10 @@
|
||||
import {ComponentRef, EmbeddedViewRef, Injector} from '../core';
|
||||
|
||||
import {assertNotNull} from './assert';
|
||||
import {NG_HOST_SYMBOL, createError, createViewState, directive, elementHost, enterView, leaveView} from './instructions';
|
||||
import {NG_HOST_SYMBOL, createError, createViewState, directive, enterView, hostElement, leaveView, locateHostElement, renderComponentOrTemplate} from './instructions';
|
||||
import {LElement} from './l_node';
|
||||
import {ComponentDef, ComponentType} from './public_interfaces';
|
||||
import {RElement, Renderer3, RendererFactory3} from './renderer';
|
||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './renderer';
|
||||
import {notImplemented, stringify} from './util';
|
||||
|
||||
|
||||
@ -22,10 +22,8 @@ import {notImplemented, stringify} from './util';
|
||||
*/
|
||||
export interface CreateComponentOptionArgs {
|
||||
/**
|
||||
* Which renderer to use.
|
||||
* Which renderer factory to use.
|
||||
*/
|
||||
renderer?: Renderer3;
|
||||
|
||||
rendererFactory?: RendererFactory3;
|
||||
|
||||
/**
|
||||
@ -138,13 +136,16 @@ export const NULL_INJECTOR: Injector = {
|
||||
*/
|
||||
export function renderComponent<T>(
|
||||
componentType: ComponentType<T>, opts: CreateComponentOptionArgs = {}): T {
|
||||
const renderer = opts.renderer || document;
|
||||
const rendererFactory = opts.rendererFactory || domRendererFactory3;
|
||||
const componentDef = componentType.ngComponentDef;
|
||||
let component: T;
|
||||
const oldView = enterView(createViewState(-1, renderer, []), null);
|
||||
const hostNode = locateHostElement(rendererFactory, opts.host || componentDef.tag);
|
||||
const oldView = enterView(
|
||||
createViewState(-1, rendererFactory.createRenderer(hostNode, componentDef.rendererType), []),
|
||||
null !);
|
||||
try {
|
||||
// Create element node at index 0 in data array
|
||||
elementHost(opts.host || componentDef.tag, componentDef);
|
||||
hostElement(hostNode, componentDef);
|
||||
// Create directive instance with n() and store at index 1 in data array (el is 0)
|
||||
component = directive(1, componentDef.n(), componentDef);
|
||||
} finally {
|
||||
@ -163,15 +164,8 @@ export function detectChanges<T>(component: T) {
|
||||
createError('Not a directive instance', component);
|
||||
}
|
||||
ngDevMode && assertNotNull(hostNode.data, 'hostNode.data');
|
||||
const oldView = enterView(hostNode.view !, hostNode);
|
||||
try {
|
||||
// Element was stored at 0 and directive was stored at 1 in renderComponent
|
||||
// so to refresh the component, r() needs to be called with (1, 0)
|
||||
(component.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
|
||||
isDirty = false;
|
||||
} finally {
|
||||
leaveView(oldView);
|
||||
}
|
||||
renderComponentOrTemplate(hostNode, hostNode.view, component);
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
let isDirty = false;
|
||||
|
@ -18,9 +18,9 @@ import {NgStaticData, LNodeStatic, LContainerStatic, InitialInputData, InitialIn
|
||||
import {assertNodeType} from './node_assert';
|
||||
import {appendChild, insertChild, insertView, processProjectedNode, removeView} from './node_manipulation';
|
||||
import {isNodeMatchingSelector} from './node_selector_matcher';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef} from './public_interfaces';
|
||||
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef} from './public_interfaces';
|
||||
import {QueryList, QueryState_} from './query';
|
||||
import {RComment, RElement, RText, Renderer3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
|
||||
import {RComment, RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './renderer';
|
||||
import {isDifferent, stringify} from './util';
|
||||
|
||||
export {queryRefresh} from './query';
|
||||
@ -73,6 +73,7 @@ let nextNgElementId = 0;
|
||||
* Renderer2.
|
||||
*/
|
||||
let renderer: Renderer3;
|
||||
let rendererFactory: RendererFactory3;
|
||||
|
||||
/** Used to set the parent property when nodes are created. */
|
||||
let previousOrParentNode: LNode;
|
||||
@ -278,18 +279,44 @@ export function createLNode(
|
||||
/**
|
||||
*
|
||||
* @param host Existing node to render into.
|
||||
* @param renderer Renderer to use.
|
||||
* @param template Template function with the instructions.
|
||||
* @param context to pass into the template.
|
||||
*/
|
||||
export function renderTemplate<T>(host: LElement, template: ComponentTemplate<T>, context: T) {
|
||||
export function renderTemplate<T>(
|
||||
hostNode: RElement, template: ComponentTemplate<T>, context: T,
|
||||
providedRendererFactory: RendererFactory3, host: LElement | null): LElement {
|
||||
if (host == null) {
|
||||
rendererFactory = providedRendererFactory;
|
||||
host = createLNode(
|
||||
null, LNodeFlags.Element, hostNode,
|
||||
createViewState(-1, providedRendererFactory.createRenderer(null, null), []));
|
||||
}
|
||||
const hostView = host.data !;
|
||||
ngDevMode && assertNotEqual(hostView, null, 'hostView');
|
||||
hostView.ngStaticData = getTemplateStatic(template);
|
||||
const oldView = enterView(hostView, host);
|
||||
renderComponentOrTemplate(host, hostView, context, template);
|
||||
return host;
|
||||
}
|
||||
|
||||
export function renderComponentOrTemplate<T>(
|
||||
node: LElement, viewState: ViewState, componentOrContext: T, template?: ComponentTemplate<T>) {
|
||||
const oldView = enterView(viewState, node);
|
||||
try {
|
||||
template(context, creationMode);
|
||||
if (rendererFactory.begin) {
|
||||
rendererFactory.begin();
|
||||
}
|
||||
if (template) {
|
||||
ngStaticData = template.ngStaticData || (template.ngStaticData = [] as never);
|
||||
template(componentOrContext !, creationMode);
|
||||
} else {
|
||||
// Element was stored at 0 and directive was stored at 1 in renderComponent
|
||||
// so to refresh the component, r() needs to be called with (1, 0)
|
||||
(componentOrContext.constructor as ComponentType<T>).ngComponentDef.r(1, 0);
|
||||
}
|
||||
} finally {
|
||||
if (rendererFactory.end) {
|
||||
rendererFactory.end();
|
||||
}
|
||||
leaveView(oldView);
|
||||
}
|
||||
}
|
||||
@ -406,7 +433,10 @@ export function elementStart(
|
||||
let componentView: ViewState|null = null;
|
||||
if (isHostElement) {
|
||||
const ngStaticData = getTemplateStatic((nameOrComponentDef as ComponentDef<any>).template);
|
||||
componentView = addToViewTree(createViewState(-1, renderer, ngStaticData));
|
||||
componentView = addToViewTree(createViewState(
|
||||
-1, rendererFactory.createRenderer(
|
||||
native, (nameOrComponentDef as ComponentDef<any>).rendererType),
|
||||
ngStaticData));
|
||||
}
|
||||
|
||||
// Only component views should be added to the view tree directly. Embedded views are
|
||||
@ -453,16 +483,19 @@ export function createError(text: string, token: any) {
|
||||
|
||||
|
||||
/**
|
||||
* Used for bootstrapping existing nodes into rendering pipeline.
|
||||
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
||||
*
|
||||
* @param elementOrSelector Render element or CSS selector to locate the element.
|
||||
*/
|
||||
export function elementHost(elementOrSelector: RElement | string, def: ComponentDef<any>) {
|
||||
export function locateHostElement(
|
||||
factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null {
|
||||
ngDevMode && assertDataInRange(-1);
|
||||
rendererFactory = factory;
|
||||
const defaultRenderer = factory.createRenderer(null, null);
|
||||
const rNode = typeof elementOrSelector === 'string' ?
|
||||
((renderer as ProceduralRenderer3).selectRootElement ?
|
||||
(renderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
|
||||
(renderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
|
||||
((defaultRenderer as ProceduralRenderer3).selectRootElement ?
|
||||
(defaultRenderer as ProceduralRenderer3).selectRootElement(elementOrSelector) :
|
||||
(defaultRenderer as ObjectOrientedRenderer3).querySelector !(elementOrSelector)) :
|
||||
elementOrSelector;
|
||||
if (ngDevMode && !rNode) {
|
||||
if (typeof elementOrSelector === 'string') {
|
||||
@ -471,6 +504,15 @@ export function elementHost(elementOrSelector: RElement | string, def: Component
|
||||
throw createError('Host node is required:', elementOrSelector);
|
||||
}
|
||||
}
|
||||
return rNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the host LNode..
|
||||
*
|
||||
* @param rNode Render host element.
|
||||
*/
|
||||
export function hostElement(rNode: RElement | null, def: ComponentDef<any>) {
|
||||
createLNode(
|
||||
0, LNodeFlags.Element, rNode, createViewState(-1, renderer, getTemplateStatic(def.template)));
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Type} from '../core';
|
||||
|
||||
import {RendererType2, Type} from '../core';
|
||||
import {resolveRendererType2} from '../view/util';
|
||||
import {componentRefresh, diPublic} from './instructions';
|
||||
|
||||
|
||||
@ -108,6 +108,13 @@ export interface ComponentDef<T> extends DirectiveDef<T> {
|
||||
* NOTE: only used with component directives.
|
||||
*/
|
||||
template: ComponentTemplate<T>;
|
||||
|
||||
/**
|
||||
* Renderer type data of the component.
|
||||
*
|
||||
* NOTE: only used with component directives.
|
||||
*/
|
||||
rendererType: RendererType2|null;
|
||||
}
|
||||
|
||||
export interface DirectiveDefArgs<T> {
|
||||
@ -125,6 +132,7 @@ export interface ComponentDefArgs<T> extends DirectiveDefArgs<T> {
|
||||
template: ComponentTemplate<T>;
|
||||
refresh?: (this: ComponentDef<T>, directiveIndex: number, elementIndex: number) => void;
|
||||
features?: ComponentDefFeature[];
|
||||
rendererType?: RendererType2;
|
||||
}
|
||||
|
||||
export type DirectiveDefFeature = <T>(directiveDef: DirectiveDef<T>) => void;
|
||||
@ -156,6 +164,7 @@ export function defineComponent<T>(componentDefinition: ComponentDefArgs<T>): Co
|
||||
inputs: invertObject(componentDefinition.inputs),
|
||||
outputs: invertObject(componentDefinition.outputs),
|
||||
methods: invertObject(componentDefinition.methods),
|
||||
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
|
||||
};
|
||||
const feature = componentDefinition.features;
|
||||
feature && feature.forEach((fn) => fn(def));
|
||||
|
@ -6,7 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DirectiveDef} from '@angular/core/src/render3/public_interfaces';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
import * as viewEngine from '../core';
|
||||
@ -15,6 +14,7 @@ import {assertNotNull} from './assert';
|
||||
import {injectElementRefForNode} from './di';
|
||||
import {QueryState} from './interfaces';
|
||||
import {LContainer, LElement, LNode, LNodeFlags, LView} from './l_node';
|
||||
import {DirectiveDef} from './public_interfaces';
|
||||
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* it will be easy to implement such API.
|
||||
*/
|
||||
|
||||
import {RendererStyleFlags2} from '../core';
|
||||
import {RendererStyleFlags2, RendererType2, ViewEncapsulation} from '../core';
|
||||
import {ComponentDef} from './public_interfaces';
|
||||
|
||||
// TODO: cleanup once the code is merged in angular/angular
|
||||
@ -68,11 +68,16 @@ export interface ProceduralRenderer3 {
|
||||
}
|
||||
|
||||
export interface RendererFactory3 {
|
||||
createRenderer(hostElement: RElement, componentDef: ComponentDef<any>): Renderer3;
|
||||
createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3;
|
||||
begin?(): void;
|
||||
end?(): void;
|
||||
}
|
||||
|
||||
export const domRendererFactory3: RendererFactory3 = {
|
||||
createRenderer: (hostElement: RElement | null, rendererType: RendererType2 | null):
|
||||
Renderer3 => { return document;}
|
||||
};
|
||||
|
||||
/** Subset of API needed for appending elements and text nodes. */
|
||||
export interface RNode {
|
||||
removeChild(oldChild: RNode): void;
|
||||
|
Reference in New Issue
Block a user