Skip to content

Commit 14d7844

Browse files
tboschmhevery
authored andcommitted
feat(core): view engine - integrate with ComponentFactory (angular#14237)
`ComponentFactory`s can now be created from a `ViewDefinitionFactory` via `RefFactory.createComponentFactory`. This commit also: - splits `Services` into `Refs` and `RootData` - changes `ViewState` into a bitmask - implements `ViewContainerRef.move` Part of angular#14013 PR Close angular#14237
1 parent 388afa4 commit 14d7844

File tree

26 files changed

+618
-353
lines changed

26 files changed

+618
-353
lines changed

modules/@angular/core/src/linker/component_factory.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,10 @@ export class ComponentFactory<C> {
9595
/** @internal */
9696
_viewClass: Type<AppView<any>>;
9797
constructor(
98-
public selector: string, _viewClass: Type<AppView<any>>, private _componentType: Type<any>) {
98+
public selector: string, _viewClass: Type<AppView<any>>, public componentType: Type<any>) {
9999
this._viewClass = _viewClass;
100100
}
101101

102-
get componentType(): Type<any> { return this._componentType; }
103-
104102
/**
105103
* Creates a new component.
106104
*/

modules/@angular/core/src/view/element.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import {isDevMode} from '../application_ref';
1010
import {SecurityContext} from '../security';
1111

12-
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, EntryAction, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, ViewData, ViewDefinition, ViewFlags, asElementData} from './types';
12+
import {BindingDef, BindingType, DebugContext, DisposableFn, ElementData, ElementOutputDef, EntryAction, NodeData, NodeDef, NodeFlags, NodeType, QueryValueType, Refs, ViewData, ViewDefinition, ViewFlags, asElementData} from './types';
1313
import {checkAndUpdateBinding, dispatchEvent, entryAction, setBindingDebugInfo, setCurrentNode, sliceErrorStack, unwrapValue} from './util';
1414

1515
export function anchorDef(
@@ -129,19 +129,30 @@ export function elementDef(
129129
}
130130

131131
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
132-
const parentNode =
133-
def.parent != null ? asElementData(view, def.parent).renderElement : renderHost;
134132
const elDef = def.element;
133+
const rootSelectorOrNode = view.root.selectorOrNode;
135134
let el: any;
136-
if (view.renderer) {
137-
const debugContext =
138-
isDevMode() ? view.services.createDebugContext(view, def.index) : undefined;
139-
el = elDef.name ? view.renderer.createElement(parentNode, elDef.name, debugContext) :
140-
view.renderer.createTemplateAnchor(parentNode, debugContext);
135+
if (view.parent || !rootSelectorOrNode) {
136+
const parentNode =
137+
def.parent != null ? asElementData(view, def.parent).renderElement : renderHost;
138+
if (view.renderer) {
139+
const debugContext = isDevMode() ? Refs.createDebugContext(view, def.index) : undefined;
140+
el = elDef.name ? view.renderer.createElement(parentNode, elDef.name, debugContext) :
141+
view.renderer.createTemplateAnchor(parentNode, debugContext);
142+
} else {
143+
el = elDef.name ? document.createElement(elDef.name) : document.createComment('');
144+
if (parentNode) {
145+
parentNode.appendChild(el);
146+
}
147+
}
141148
} else {
142-
el = elDef.name ? document.createElement(elDef.name) : document.createComment('');
143-
if (parentNode) {
144-
parentNode.appendChild(el);
149+
if (view.renderer) {
150+
const debugContext = isDevMode() ? Refs.createDebugContext(view, def.index) : undefined;
151+
el = view.renderer.selectRootElement(rootSelectorOrNode, debugContext);
152+
} else {
153+
el = typeof rootSelectorOrNode === 'string' ? document.querySelector(rootSelectorOrNode) :
154+
rootSelectorOrNode;
155+
el.textContent = '';
145156
}
146157
}
147158
if (elDef.attrs) {
@@ -269,7 +280,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
269280
function setElementAttribute(
270281
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
271282
const securityContext = binding.securityContext;
272-
let renderValue = securityContext ? view.services.sanitize(securityContext, value) : value;
283+
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
273284
renderValue = renderValue != null ? renderValue.toString() : null;
274285
if (view.renderer) {
275286
view.renderer.setElementAttribute(renderNode, name, renderValue);
@@ -296,7 +307,7 @@ function setElementClass(view: ViewData, renderNode: any, name: string, value: b
296307

297308
function setElementStyle(
298309
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
299-
let renderValue = view.services.sanitize(SecurityContext.STYLE, value);
310+
let renderValue = view.root.sanitizer.sanitize(SecurityContext.STYLE, value);
300311
if (renderValue != null) {
301312
renderValue = renderValue.toString();
302313
const unit = binding.suffix;
@@ -322,7 +333,7 @@ function setElementStyle(
322333
function setElementProperty(
323334
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
324335
const securityContext = binding.securityContext;
325-
let renderValue = securityContext ? view.services.sanitize(securityContext, value) : value;
336+
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
326337
if (view.renderer) {
327338
view.renderer.setElementProperty(renderNode, name, renderValue);
328339
if (isDevMode() && (view.def.flags & ViewFlags.DirectDom) === 0) {

modules/@angular/core/src/view/errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function viewDebugError(msg: string, context: DebugContext): ViewDebugErr
3535
const err = new Error(msg) as any;
3636
err.context = context;
3737
err.stack = context.source;
38-
context.view.state = ViewState.Errored;
38+
context.view.state |= ViewState.Errored;
3939
return err;
4040
}
4141

modules/@angular/core/src/view/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ export {queryDef} from './query';
1414
export {textDef} from './text';
1515
export {rootRenderNodes, setCurrentNode} from './util';
1616
export {checkAndUpdateView, checkNoChangesView, checkNodeDynamic, checkNodeInline, createEmbeddedView, createRootView, destroyView, viewDef} from './view';
17-
export {attachEmbeddedView, detachEmbeddedView} from './view_attach';
18-
17+
export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
1918
export * from './types';
20-
export {DefaultServices} from './services';
19+
20+
import {createRefs} from './refs';
21+
import {Refs} from './types';
22+
23+
Refs.setInstance(createRefs());
24+
25+
export const createComponentFactory: typeof Refs.createComponentFactory =
26+
Refs.createComponentFactory;

modules/@angular/core/src/view/provider.ts

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import {Renderer} from '../render/api';
1717
import {Type} from '../type';
1818

1919
import {queryDef} from './query';
20-
import {BindingDef, BindingType, DepDef, DepFlags, DisposableFn, EntryAction, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderOutputDef, ProviderType, QueryBindingType, QueryDef, QueryValueType, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
21-
import {checkAndUpdateBinding, dispatchEvent, entryAction, findElementDef, setBindingDebugInfo, setCurrentNode, unwrapValue} from './util';
20+
import {BindingDef, BindingType, DepDef, DepFlags, DisposableFn, EntryAction, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderOutputDef, ProviderType, QueryBindingType, QueryDef, QueryValueType, Refs, RootData, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
21+
import {checkAndUpdateBinding, dispatchEvent, entryAction, findElementDef, parentDiIndex, setBindingDebugInfo, setCurrentNode, unwrapValue} from './util';
2222

2323
const _tokenKeyCache = new Map<any, string>();
2424

@@ -169,7 +169,7 @@ export function checkAndUpdateProviderInline(
169169
if (changes) {
170170
provider.ngOnChanges(changes);
171171
}
172-
if (view.state === ViewState.FirstCheck && (def.flags & NodeFlags.OnInit)) {
172+
if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
173173
provider.ngOnInit();
174174
}
175175
if (def.flags & NodeFlags.DoCheck) {
@@ -186,7 +186,7 @@ export function checkAndUpdateProviderDynamic(view: ViewData, def: NodeDef, valu
186186
if (changes) {
187187
provider.ngOnChanges(changes);
188188
}
189-
if (view.state === ViewState.FirstCheck && (def.flags & NodeFlags.OnInit)) {
189+
if ((view.state & ViewState.FirstCheck) && (def.flags & NodeFlags.OnInit)) {
190190
provider.ngOnInit();
191191
}
192192
if (def.flags & NodeFlags.DoCheck) {
@@ -290,16 +290,18 @@ function callFactory(
290290
}
291291

292292
export function resolveDep(
293-
view: ViewData, requestNodeIndex: number, elIndex: number, depDef: DepDef): any {
294-
const notFoundValue = depDef.flags & DepFlags.Optional ? null : Injector.THROW_IF_NOT_FOUND;
293+
view: ViewData, requestNodeIndex: number, elIndex: number, depDef: DepDef,
294+
notFoundValue = Injector.THROW_IF_NOT_FOUND): any {
295+
const startView = view;
296+
if (depDef.flags & DepFlags.Optional) {
297+
notFoundValue = null;
298+
}
295299
const tokenKey = depDef.tokenKey;
296300

297301
if (depDef.flags & DepFlags.SkipSelf) {
298302
requestNodeIndex = null;
299-
const elDef = view.def.nodes[elIndex];
300-
if (elDef.parent != null) {
301-
elIndex = elDef.parent;
302-
} else {
303+
elIndex = view.def.nodes[elIndex].parent;
304+
while (elIndex == null && view) {
303305
elIndex = parentDiIndex(view);
304306
view = view.parent;
305307
}
@@ -317,9 +319,9 @@ export function resolveDep(
317319
case ElementRefTokenKey:
318320
return new ElementRef(asElementData(view, elIndex).renderElement);
319321
case ViewContainerRefTokenKey:
320-
return view.services.createViewContainerRef(asElementData(view, elIndex));
322+
return Refs.createViewContainerRef(view, elIndex);
321323
case TemplateRefTokenKey:
322-
return view.services.createTemplateRef(view, elDef);
324+
return Refs.createTemplateRef(view, elDef);
323325
case ChangeDetectorRefTokenKey:
324326
let cdView = view;
325327
// If we are still checking dependencies on the initial element...
@@ -330,9 +332,9 @@ export function resolveDep(
330332
}
331333
}
332334
// A ViewRef is also a ChangeDetectorRef
333-
return view.services.createViewRef(cdView);
335+
return Refs.createViewRef(cdView);
334336
case InjectorRefTokenKey:
335-
return createInjector(view, elIndex);
337+
return Refs.createInjector(view, elIndex);
336338
default:
337339
const providerIndex = elDef.element.providerIndices[tokenKey];
338340
if (providerIndex != null) {
@@ -347,34 +349,7 @@ export function resolveDep(
347349
elIndex = parentDiIndex(view);
348350
view = view.parent;
349351
}
350-
return Injector.NULL.get(depDef.token, notFoundValue);
351-
}
352-
353-
/**
354-
* for component views, this is the same as parentIndex.
355-
* for embedded views, this is the index of the parent node
356-
* that contains the view container.
357-
*/
358-
function parentDiIndex(view: ViewData): number {
359-
if (view.parent) {
360-
const parentNodeDef = view.def.nodes[view.parentIndex];
361-
return parentNodeDef.element && parentNodeDef.element.template ? parentNodeDef.parent :
362-
parentNodeDef.index;
363-
}
364-
return view.parentIndex;
365-
}
366-
367-
export function createInjector(view: ViewData, elIndex: number): Injector {
368-
return new Injector_(view, elIndex);
369-
}
370-
371-
class Injector_ implements Injector {
372-
constructor(private view: ViewData, private elIndex: number) {}
373-
get(token: any, notFoundValue?: any): any {
374-
return resolveDep(
375-
this.view, undefined, this.elIndex,
376-
{flags: DepFlags.None, token, tokenKey: tokenKey(token)});
377-
}
352+
return startView.root.injector.get(depDef.token, notFoundValue);
378353
}
379354

380355
function checkAndUpdateProp(
@@ -385,8 +360,9 @@ function checkAndUpdateProp(
385360
if (def.flags & NodeFlags.OnChanges) {
386361
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
387362
changed = checkAndUpdateBinding(view, def, bindingIdx, value);
388-
change =
389-
changed ? new SimpleChange(oldValue, value, view.state === ViewState.FirstCheck) : null;
363+
change = changed ?
364+
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0) :
365+
null;
390366
} else {
391367
changed = checkAndUpdateBinding(view, def, bindingIdx, value);
392368
}

modules/@angular/core/src/view/query.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {QueryList} from '../linker/query_list';
1111
import {TemplateRef} from '../linker/template_ref';
1212
import {ViewContainerRef} from '../linker/view_container_ref';
1313

14-
import {NodeDef, NodeFlags, NodeType, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData, asElementData, asProviderData, asQueryList} from './types';
14+
import {NodeDef, NodeFlags, NodeType, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, Refs, ViewData, asElementData, asProviderData, asQueryList} from './types';
1515
import {declaredViewContainer} from './util';
1616

1717
export function queryDef(
@@ -158,10 +158,10 @@ export function getQueryValue(view: ViewData, nodeDef: NodeDef, queryId: string)
158158
value = new ElementRef(asElementData(view, nodeDef.index).renderElement);
159159
break;
160160
case QueryValueType.TemplateRef:
161-
value = view.services.createTemplateRef(view, nodeDef);
161+
value = Refs.createTemplateRef(view, nodeDef);
162162
break;
163163
case QueryValueType.ViewContainerRef:
164-
value = view.services.createViewContainerRef(asElementData(view, nodeDef.index));
164+
value = Refs.createViewContainerRef(view, nodeDef.index);
165165
break;
166166
case QueryValueType.Provider:
167167
value = asProviderData(view, nodeDef.index).instance;

0 commit comments

Comments
 (0)