refactor(core): view engine - misc
- fix bug when detaching view from `ApplicationRef` - fix integration of adding `ng-reflect` attributes in debug mode.
This commit is contained in:
parent
5049a50bf6
commit
ab3527c99b
|
@ -255,7 +255,7 @@ export class Identifiers {
|
|||
static pureArrayDef:
|
||||
IdentifierSpec = {name: 'ɵpureArrayDef', moduleUrl: CORE, runtime: ɵpureArrayDef};
|
||||
static pureObjectDef:
|
||||
IdentifierSpec = {name: 'ɵpureObjectRef', moduleUrl: CORE, runtime: ɵpureObjectDef};
|
||||
IdentifierSpec = {name: 'ɵpureObjectDef', moduleUrl: CORE, runtime: ɵpureObjectDef};
|
||||
static purePipeDef:
|
||||
IdentifierSpec = {name: 'ɵpurePipeDef', moduleUrl: CORE, runtime: ɵpurePipeDef};
|
||||
static pipeDef: IdentifierSpec = {name: 'ɵpipeDef', moduleUrl: CORE, runtime: ɵpipeDef};
|
||||
|
|
|
@ -447,7 +447,9 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver, BuiltinConverter
|
|||
dirAst.directive.queries.forEach((query, queryIndex) => {
|
||||
let flags = NodeFlags.HasContentQuery;
|
||||
const queryId = dirAst.contentQueryStartId + queryIndex;
|
||||
if (queryIds.staticQueryIds.has(queryId)) {
|
||||
// Note: We only make queries static that query for a single item.
|
||||
// This is because of backwards compatibility with the old view compiler...
|
||||
if (queryIds.staticQueryIds.has(queryId) && query.first) {
|
||||
flags |= NodeFlags.HasStaticQuery;
|
||||
} else {
|
||||
flags |= NodeFlags.HasDynamicQuery;
|
||||
|
|
|
@ -493,7 +493,7 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||
detachView(viewRef: ViewRef): void {
|
||||
const view = (viewRef as InternalViewRef);
|
||||
ListWrapper.remove(this._views, view);
|
||||
view.detachFromContainer();
|
||||
view.detachFromAppRef();
|
||||
}
|
||||
|
||||
bootstrap<C>(componentOrFactory: ComponentFactory<C>|Type<C>): ComponentRef<C> {
|
||||
|
|
|
@ -89,7 +89,7 @@ export abstract class EmbeddedViewRef<C> extends ViewRef {
|
|||
}
|
||||
|
||||
export interface InternalViewRef extends ViewRef {
|
||||
detachFromContainer(): void;
|
||||
detachFromAppRef(): void;
|
||||
attachToAppRef(appRef: ApplicationRef): void;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ export class ViewRef_<C> implements EmbeddedViewRef<C>, ChangeDetectorRef, Inter
|
|||
|
||||
destroy() { this._view.detachAndDestroy(); }
|
||||
|
||||
detachFromContainer() { this._view.detach(); }
|
||||
detachFromAppRef() { this._view.detach(); }
|
||||
|
||||
attachToAppRef(appRef: ApplicationRef) { this._view.attachToAppRef(appRef); }
|
||||
}
|
||||
|
|
|
@ -213,29 +213,33 @@ function renderEventHandlerClosure(view: ViewData, index: number, eventName: str
|
|||
|
||||
export function checkAndUpdateElementInline(
|
||||
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any, v8: any, v9: any) {
|
||||
v7: any, v8: any, v9: any): boolean {
|
||||
const bindLen = def.bindings.length;
|
||||
if (bindLen > 0) checkAndUpdateElementValue(view, def, 0, v0);
|
||||
if (bindLen > 1) checkAndUpdateElementValue(view, def, 1, v1);
|
||||
if (bindLen > 2) checkAndUpdateElementValue(view, def, 2, v2);
|
||||
if (bindLen > 3) checkAndUpdateElementValue(view, def, 3, v3);
|
||||
if (bindLen > 4) checkAndUpdateElementValue(view, def, 4, v4);
|
||||
if (bindLen > 5) checkAndUpdateElementValue(view, def, 5, v5);
|
||||
if (bindLen > 6) checkAndUpdateElementValue(view, def, 6, v6);
|
||||
if (bindLen > 7) checkAndUpdateElementValue(view, def, 7, v7);
|
||||
if (bindLen > 8) checkAndUpdateElementValue(view, def, 8, v8);
|
||||
if (bindLen > 9) checkAndUpdateElementValue(view, def, 9, v9);
|
||||
let changed = false;
|
||||
if (bindLen > 0 && checkAndUpdateElementValue(view, def, 0, v0)) changed = true;
|
||||
if (bindLen > 1 && checkAndUpdateElementValue(view, def, 1, v1)) changed = true;
|
||||
if (bindLen > 2 && checkAndUpdateElementValue(view, def, 2, v2)) changed = true;
|
||||
if (bindLen > 3 && checkAndUpdateElementValue(view, def, 3, v3)) changed = true;
|
||||
if (bindLen > 4 && checkAndUpdateElementValue(view, def, 4, v4)) changed = true;
|
||||
if (bindLen > 5 && checkAndUpdateElementValue(view, def, 5, v5)) changed = true;
|
||||
if (bindLen > 6 && checkAndUpdateElementValue(view, def, 6, v6)) changed = true;
|
||||
if (bindLen > 7 && checkAndUpdateElementValue(view, def, 7, v7)) changed = true;
|
||||
if (bindLen > 8 && checkAndUpdateElementValue(view, def, 8, v8)) changed = true;
|
||||
if (bindLen > 9 && checkAndUpdateElementValue(view, def, 9, v9)) changed = true;
|
||||
return changed;
|
||||
}
|
||||
|
||||
export function checkAndUpdateElementDynamic(view: ViewData, def: NodeDef, values: any[]) {
|
||||
export function checkAndUpdateElementDynamic(view: ViewData, def: NodeDef, values: any[]): boolean {
|
||||
let changed = false;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
checkAndUpdateElementValue(view, def, i, values[i]);
|
||||
if (checkAndUpdateElementValue(view, def, i, values[i])) changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: number, value: any) {
|
||||
if (!checkAndUpdateBinding(view, def, bindingIdx, value)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const binding = def.bindings[bindingIdx];
|
||||
const elData = asElementData(view, def.index);
|
||||
|
@ -258,6 +262,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
|
|||
setElementProperty(elData.componentView, binding, renderNode, name, value);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function setElementAttribute(
|
||||
|
|
|
@ -16,7 +16,7 @@ import {Renderer as RendererV1, RendererFactoryV2, RendererTypeV2, RendererV2} f
|
|||
|
||||
import {createChangeDetectorRef, createInjector, createRendererV1, createTemplateRef, createViewContainerRef} from './refs';
|
||||
import {BindingDef, BindingType, DepDef, DepFlags, DisposableFn, NodeData, NodeDef, NodeFlags, NodeType, OutputDef, OutputType, ProviderData, ProviderType, QueryBindingType, QueryDef, QueryValueType, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewState, asElementData, asProviderData} from './types';
|
||||
import {checkAndUpdateBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
||||
import {checkBinding, dispatchEvent, filterQueryId, isComponentView, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
|
||||
|
||||
const RendererV1TokenKey = tokenKey(RendererV1);
|
||||
const RendererV2TokenKey = tokenKey(RendererV2);
|
||||
|
@ -156,21 +156,52 @@ function eventHandlerClosure(view: ViewData, index: number, eventName: string) {
|
|||
|
||||
export function checkAndUpdateDirectiveInline(
|
||||
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any, v8: any, v9: any) {
|
||||
v7: any, v8: any, v9: any): boolean {
|
||||
const providerData = asProviderData(view, def.index);
|
||||
const directive = providerData.instance;
|
||||
let changed = false;
|
||||
let changes: SimpleChanges;
|
||||
const bindLen = def.bindings.length;
|
||||
if (bindLen > 0) changes = checkAndUpdateProp(view, providerData, def, 0, v0, changes);
|
||||
if (bindLen > 1) changes = checkAndUpdateProp(view, providerData, def, 1, v1, changes);
|
||||
if (bindLen > 2) changes = checkAndUpdateProp(view, providerData, def, 2, v2, changes);
|
||||
if (bindLen > 3) changes = checkAndUpdateProp(view, providerData, def, 3, v3, changes);
|
||||
if (bindLen > 4) changes = checkAndUpdateProp(view, providerData, def, 4, v4, changes);
|
||||
if (bindLen > 5) changes = checkAndUpdateProp(view, providerData, def, 5, v5, changes);
|
||||
if (bindLen > 6) changes = checkAndUpdateProp(view, providerData, def, 6, v6, changes);
|
||||
if (bindLen > 7) changes = checkAndUpdateProp(view, providerData, def, 7, v7, changes);
|
||||
if (bindLen > 8) changes = checkAndUpdateProp(view, providerData, def, 8, v8, changes);
|
||||
if (bindLen > 9) changes = checkAndUpdateProp(view, providerData, def, 9, v9, changes);
|
||||
if (bindLen > 0 && checkBinding(view, def, 0, v0)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 0, v0, changes);
|
||||
};
|
||||
if (bindLen > 1 && checkBinding(view, def, 1, v1)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 1, v1, changes);
|
||||
};
|
||||
if (bindLen > 2 && checkBinding(view, def, 2, v2)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 2, v2, changes);
|
||||
};
|
||||
if (bindLen > 3 && checkBinding(view, def, 3, v3)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 3, v3, changes);
|
||||
};
|
||||
if (bindLen > 4 && checkBinding(view, def, 4, v4)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 4, v4, changes);
|
||||
};
|
||||
if (bindLen > 5 && checkBinding(view, def, 5, v5)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 5, v5, changes);
|
||||
};
|
||||
if (bindLen > 6 && checkBinding(view, def, 6, v6)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 6, v6, changes);
|
||||
};
|
||||
if (bindLen > 7 && checkBinding(view, def, 7, v7)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 7, v7, changes);
|
||||
};
|
||||
if (bindLen > 8 && checkBinding(view, def, 8, v8)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 8, v8, changes);
|
||||
};
|
||||
if (bindLen > 9 && checkBinding(view, def, 9, v9)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 9, v9, changes);
|
||||
};
|
||||
if (changes) {
|
||||
directive.ngOnChanges(changes);
|
||||
}
|
||||
|
@ -180,14 +211,20 @@ export function checkAndUpdateDirectiveInline(
|
|||
if (def.flags & NodeFlags.DoCheck) {
|
||||
directive.ngDoCheck();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
export function checkAndUpdateDirectiveDynamic(view: ViewData, def: NodeDef, values: any[]) {
|
||||
export function checkAndUpdateDirectiveDynamic(
|
||||
view: ViewData, def: NodeDef, values: any[]): boolean {
|
||||
const providerData = asProviderData(view, def.index);
|
||||
const directive = providerData.instance;
|
||||
let changed = false;
|
||||
let changes: SimpleChanges;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
changes = checkAndUpdateProp(view, providerData, def, i, values[i], changes);
|
||||
if (checkBinding(view, def, i, values[i])) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, i, values[i], changes);
|
||||
}
|
||||
}
|
||||
if (changes) {
|
||||
directive.ngOnChanges(changes);
|
||||
|
@ -198,6 +235,7 @@ export function checkAndUpdateDirectiveDynamic(view: ViewData, def: NodeDef, val
|
|||
if (def.flags & NodeFlags.DoCheck) {
|
||||
directive.ngDoCheck();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function _createProviderInstance(view: ViewData, def: NodeDef): any {
|
||||
|
@ -366,38 +404,29 @@ function findCompView(view: ViewData, elDef: NodeDef, allowPrivateServices: bool
|
|||
return compView;
|
||||
}
|
||||
|
||||
function checkAndUpdateProp(
|
||||
function updateProp(
|
||||
view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any,
|
||||
changes: SimpleChanges): SimpleChanges {
|
||||
let change: SimpleChange;
|
||||
let changed: boolean;
|
||||
if (def.flags & NodeFlags.IsComponent) {
|
||||
const compView = asElementData(view, def.parent.index).componentView;
|
||||
if (compView.def.flags & ViewFlags.OnPush) {
|
||||
compView.state |= ViewState.ChecksEnabled;
|
||||
}
|
||||
}
|
||||
const binding = def.bindings[bindingIdx];
|
||||
const propName = binding.name;
|
||||
// Note: This is still safe with Closure Compiler as
|
||||
// the user passed in the property name as an object has to `providerDef`,
|
||||
// so Closure Compiler will have renamed the property correctly already.
|
||||
providerData.instance[propName] = value;
|
||||
if (def.flags & NodeFlags.OnChanges) {
|
||||
changes = changes || {};
|
||||
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
|
||||
changed = checkAndUpdateBinding(view, def, bindingIdx, value);
|
||||
change = changed ?
|
||||
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0) :
|
||||
null;
|
||||
} else {
|
||||
changed = checkAndUpdateBinding(view, def, bindingIdx, value);
|
||||
}
|
||||
if (changed) {
|
||||
if (def.flags & NodeFlags.IsComponent) {
|
||||
const compView = asElementData(view, def.parent.index).componentView;
|
||||
if (compView.def.flags & ViewFlags.OnPush) {
|
||||
compView.state |= ViewState.ChecksEnabled;
|
||||
}
|
||||
}
|
||||
const binding = def.bindings[bindingIdx];
|
||||
const propName = binding.name;
|
||||
// Note: This is still safe with Closure Compiler as
|
||||
// the user passed in the property name as an object has to `providerDef`,
|
||||
// so Closure Compiler will have renamed the property correctly already.
|
||||
providerData.instance[propName] = value;
|
||||
if (change) {
|
||||
changes = changes || {};
|
||||
changes[binding.nonMinifiedName] = change;
|
||||
}
|
||||
changes[binding.nonMinifiedName] =
|
||||
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0);
|
||||
}
|
||||
view.oldValues[def.bindingIndex + bindingIdx] = value;
|
||||
return changes;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ export function createPureExpression(view: ViewData, def: NodeDef): PureExpressi
|
|||
|
||||
export function checkAndUpdatePureExpressionInline(
|
||||
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any, v8: any, v9: any) {
|
||||
v7: any, v8: any, v9: any): boolean {
|
||||
const bindings = def.bindings;
|
||||
let changed = false;
|
||||
const bindLen = bindings.length;
|
||||
|
@ -84,8 +84,8 @@ export function checkAndUpdatePureExpressionInline(
|
|||
if (bindLen > 8 && checkAndUpdateBinding(view, def, 8, v8)) changed = true;
|
||||
if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) changed = true;
|
||||
|
||||
const data = asPureExpressionData(view, def.index);
|
||||
if (changed) {
|
||||
const data = asPureExpressionData(view, def.index);
|
||||
let value: any;
|
||||
switch (def.pureExpression.type) {
|
||||
case PureExpressionType.Array:
|
||||
|
@ -152,10 +152,11 @@ export function checkAndUpdatePureExpressionInline(
|
|||
}
|
||||
data.value = value;
|
||||
}
|
||||
return data.value;
|
||||
return changed;
|
||||
}
|
||||
|
||||
export function checkAndUpdatePureExpressionDynamic(view: ViewData, def: NodeDef, values: any[]) {
|
||||
export function checkAndUpdatePureExpressionDynamic(
|
||||
view: ViewData, def: NodeDef, values: any[]): boolean {
|
||||
const bindings = def.bindings;
|
||||
let changed = false;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
|
@ -165,8 +166,8 @@ export function checkAndUpdatePureExpressionDynamic(view: ViewData, def: NodeDef
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
const data = asPureExpressionData(view, def.index);
|
||||
if (changed) {
|
||||
const data = asPureExpressionData(view, def.index);
|
||||
let value: any;
|
||||
switch (def.pureExpression.type) {
|
||||
case PureExpressionType.Array:
|
||||
|
@ -186,5 +187,5 @@ export function checkAndUpdatePureExpressionDynamic(view: ViewData, def: NodeDef
|
|||
}
|
||||
data.value = value;
|
||||
}
|
||||
return data.value;
|
||||
return changed;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ import {Type} from '../type';
|
|||
import {VERSION} from '../version';
|
||||
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types';
|
||||
import {isComponentView, renderNode, resolveViewDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util';
|
||||
import {isComponentView, markParentViewsForCheck, renderNode, resolveViewDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util';
|
||||
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView, renderDetachView} from './view_attach';
|
||||
|
||||
const EMPTY_CONTEXT = new Object();
|
||||
|
||||
|
@ -98,14 +99,13 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||
clear(): void {
|
||||
const len = this._data.embeddedViews.length;
|
||||
for (let i = len - 1; i >= 0; i--) {
|
||||
const view = Services.detachEmbeddedView(this._data, i);
|
||||
const view = detachEmbeddedView(this._data, i);
|
||||
Services.destroyView(view);
|
||||
}
|
||||
}
|
||||
|
||||
get(index: number): ViewRef { return this._getViewRef(this._data.embeddedViews[index]); }
|
||||
|
||||
private _getViewRef(view: ViewData) {
|
||||
get(index: number): ViewRef {
|
||||
const view = this._data.embeddedViews[index];
|
||||
if (view) {
|
||||
const ref = new ViewRef_(view);
|
||||
ref.attachToViewContainerRef(this);
|
||||
|
@ -135,14 +135,14 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||
insert(viewRef: ViewRef, index?: number): ViewRef {
|
||||
const viewRef_ = <ViewRef_>viewRef;
|
||||
const viewData = viewRef_._view;
|
||||
Services.attachEmbeddedView(this._data, index, viewData);
|
||||
attachEmbeddedView(this._view, this._data, index, viewData);
|
||||
viewRef_.attachToViewContainerRef(this);
|
||||
return viewRef;
|
||||
}
|
||||
|
||||
move(viewRef: ViewRef_, currentIndex: number): ViewRef {
|
||||
const previousIndex = this._data.embeddedViews.indexOf(viewRef._view);
|
||||
Services.moveEmbeddedView(this._data, previousIndex, currentIndex);
|
||||
moveEmbeddedView(this._data, previousIndex, currentIndex);
|
||||
return viewRef;
|
||||
}
|
||||
|
||||
|
@ -151,20 +151,15 @@ class ViewContainerRef_ implements ViewContainerRef {
|
|||
}
|
||||
|
||||
remove(index?: number): void {
|
||||
const viewData = Services.detachEmbeddedView(this._data, index);
|
||||
const viewData = detachEmbeddedView(this._data, index);
|
||||
if (viewData) {
|
||||
Services.destroyView(viewData);
|
||||
}
|
||||
}
|
||||
|
||||
detach(index?: number): ViewRef {
|
||||
const view = Services.detachEmbeddedView(this._data, index);
|
||||
if (view) {
|
||||
const viewRef = this._getViewRef(view);
|
||||
viewRef.detachFromContainer();
|
||||
return viewRef;
|
||||
}
|
||||
return null;
|
||||
const view = detachEmbeddedView(this._data, index);
|
||||
return view ? new ViewRef_(view) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +185,7 @@ export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef {
|
|||
|
||||
get destroyed(): boolean { return (this._view.state & ViewState.Destroyed) !== 0; }
|
||||
|
||||
markForCheck(): void { this.reattach(); }
|
||||
markForCheck(): void { markParentViewsForCheck(this._view); }
|
||||
detach(): void { this._view.state &= ~ViewState.ChecksEnabled; }
|
||||
detectChanges(): void { Services.checkAndUpdateView(this._view); }
|
||||
checkNoChanges(): void { Services.checkNoChangesView(this._view); }
|
||||
|
@ -212,9 +207,10 @@ export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef {
|
|||
Services.destroyView(this._view);
|
||||
}
|
||||
|
||||
detachFromContainer() {
|
||||
detachFromAppRef() {
|
||||
this._appRef = null;
|
||||
this._viewContainerRef = null;
|
||||
renderDetachView(this._view);
|
||||
Services.dirtyParentQueries(this._view);
|
||||
}
|
||||
|
||||
attachToAppRef(appRef: ApplicationRef) {
|
||||
|
|
|
@ -14,12 +14,11 @@ import {Sanitizer, SecurityContext} from '../security';
|
|||
|
||||
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
|
||||
import {resolveDep} from './provider';
|
||||
import {getQueryValue} from './query';
|
||||
import {dirtyParentQueries, getQueryValue} from './query';
|
||||
import {createInjector} from './refs';
|
||||
import {ArgumentType, BindingType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData} from './types';
|
||||
import {ArgumentType, BindingType, CheckType, DebugContext, DepFlags, ElementData, NodeCheckFn, NodeData, NodeDef, NodeFlags, NodeType, RootData, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asPureExpressionData} from './types';
|
||||
import {checkBinding, isComponentView, renderNode, viewParentEl} from './util';
|
||||
import {checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||
import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach';
|
||||
import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createEmbeddedView, createRootView, destroyView} from './view';
|
||||
|
||||
let initialized = false;
|
||||
|
||||
|
@ -35,14 +34,12 @@ export function initServicesIfNeeded() {
|
|||
Services.checkAndUpdateView = services.checkAndUpdateView;
|
||||
Services.checkNoChangesView = services.checkNoChangesView;
|
||||
Services.destroyView = services.destroyView;
|
||||
Services.attachEmbeddedView = services.attachEmbeddedView,
|
||||
Services.detachEmbeddedView = services.detachEmbeddedView,
|
||||
Services.moveEmbeddedView = services.moveEmbeddedView;
|
||||
Services.resolveDep = services.resolveDep;
|
||||
Services.resolveDep = resolveDep;
|
||||
Services.createDebugContext = services.createDebugContext;
|
||||
Services.handleEvent = services.handleEvent;
|
||||
Services.updateDirectives = services.updateDirectives;
|
||||
Services.updateRenderer = services.updateRenderer;
|
||||
Services.dirtyParentQueries = dirtyParentQueries;
|
||||
}
|
||||
|
||||
function createProdServices() {
|
||||
|
@ -53,16 +50,17 @@ function createProdServices() {
|
|||
checkAndUpdateView: checkAndUpdateView,
|
||||
checkNoChangesView: checkNoChangesView,
|
||||
destroyView: destroyView,
|
||||
attachEmbeddedView: attachEmbeddedView,
|
||||
detachEmbeddedView: detachEmbeddedView,
|
||||
moveEmbeddedView: moveEmbeddedView,
|
||||
resolveDep: resolveDep,
|
||||
createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex),
|
||||
handleEvent: (view: ViewData, nodeIndex: number, eventName: string, event: any) =>
|
||||
view.def.handleEvent(view, nodeIndex, eventName, event),
|
||||
updateDirectives: (check: NodeCheckFn, view: ViewData) =>
|
||||
view.def.updateDirectives(check, view),
|
||||
updateRenderer: (check: NodeCheckFn, view: ViewData) => view.def.updateRenderer(check, view),
|
||||
updateDirectives: (view: ViewData, checkType: CheckType) => view.def.updateDirectives(
|
||||
checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode :
|
||||
prodCheckNoChangesNode,
|
||||
view),
|
||||
updateRenderer: (view: ViewData, checkType: CheckType) => view.def.updateRenderer(
|
||||
checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode :
|
||||
prodCheckNoChangesNode,
|
||||
view),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -74,10 +72,6 @@ function createDebugServices() {
|
|||
checkAndUpdateView: debugCheckAndUpdateView,
|
||||
checkNoChangesView: debugCheckNoChangesView,
|
||||
destroyView: debugDestroyView,
|
||||
attachEmbeddedView: attachEmbeddedView,
|
||||
detachEmbeddedView: detachEmbeddedView,
|
||||
moveEmbeddedView: moveEmbeddedView,
|
||||
resolveDep: resolveDep,
|
||||
createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex),
|
||||
handleEvent: debugHandleEvent,
|
||||
updateDirectives: debugUpdateDirectives,
|
||||
|
@ -115,6 +109,24 @@ function createRootData(
|
|||
};
|
||||
}
|
||||
|
||||
function prodCheckAndUpdateNode(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
checkAndUpdateNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
return (nodeDef.type === NodeType.PureExpression) ? asPureExpressionData(view, nodeIndex).value :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function prodCheckNoChangesNode(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
checkNoChangesNode(view, nodeDef, argStyle, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
return (nodeDef.type === NodeType.PureExpression) ? asPureExpressionData(view, nodeIndex).value :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function debugCreateEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
|
||||
return callWithDebugContext(
|
||||
DebugAction.create, createEmbeddedView, null, [parent, anchorDef, context]);
|
||||
|
@ -158,7 +170,7 @@ function debugHandleEvent(view: ViewData, nodeIndex: number, eventName: string,
|
|||
DebugAction.handleEvent, view.def.handleEvent, null, [view, nodeIndex, eventName, event]);
|
||||
}
|
||||
|
||||
function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
|
||||
function debugUpdateDirectives(view: ViewData, checkType: CheckType) {
|
||||
if (view.state & ViewState.Destroyed) {
|
||||
throw viewDestroyedError(DebugAction[_currentAction]);
|
||||
}
|
||||
|
@ -167,15 +179,22 @@ function debugUpdateDirectives(check: NodeCheckFn, view: ViewData) {
|
|||
|
||||
function debugCheckDirectivesFn(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
||||
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
||||
if (view.def.nodes[nodeIndex].type === NodeType.Directive) {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
if (checkType === CheckType.CheckAndUpdate) {
|
||||
debugCheckAndUpdateNode(view, nodeDef, argStyle, values);
|
||||
} else {
|
||||
debugCheckNoChangesNode(view, nodeDef, argStyle, values);
|
||||
}
|
||||
if (nodeDef.type === NodeType.Directive) {
|
||||
debugSetCurrentNode(view, nextDirectiveWithBinding(view, nodeIndex));
|
||||
}
|
||||
return result;
|
||||
return (nodeDef.type === NodeType.PureExpression) ?
|
||||
asPureExpressionData(view, nodeDef.index).value :
|
||||
undefined;
|
||||
};
|
||||
}
|
||||
|
||||
function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
||||
function debugUpdateRenderer(view: ViewData, checkType: CheckType) {
|
||||
if (view.state & ViewState.Destroyed) {
|
||||
throw viewDestroyedError(DebugAction[_currentAction]);
|
||||
}
|
||||
|
@ -184,21 +203,26 @@ function debugUpdateRenderer(check: NodeCheckFn, view: ViewData) {
|
|||
|
||||
function debugCheckRenderNodeFn(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, ...values: any[]) {
|
||||
const result = debugCheckFn(check, view, nodeIndex, argStyle, values);
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
if (checkType === CheckType.CheckAndUpdate) {
|
||||
debugCheckAndUpdateNode(view, nodeDef, argStyle, values);
|
||||
} else {
|
||||
debugCheckNoChangesNode(view, nodeDef, argStyle, values);
|
||||
}
|
||||
if (nodeDef.type === NodeType.Element || nodeDef.type === NodeType.Text) {
|
||||
debugSetCurrentNode(view, nextRenderNodeWithBinding(view, nodeIndex));
|
||||
}
|
||||
return result;
|
||||
return (nodeDef.type === NodeType.PureExpression) ?
|
||||
asPureExpressionData(view, nodeDef.index).value :
|
||||
undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function debugCheckFn(
|
||||
delegate: NodeCheckFn, view: ViewData, nodeIndex: number, argStyle: ArgumentType,
|
||||
givenValues: any[]) {
|
||||
if (_currentAction === DebugAction.detectChanges) {
|
||||
function debugCheckAndUpdateNode(
|
||||
view: ViewData, nodeDef: NodeDef, argStyle: ArgumentType, givenValues: any[]): void {
|
||||
const changed = (<any>checkAndUpdateNode)(view, nodeDef, argStyle, ...givenValues);
|
||||
if (changed) {
|
||||
const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
if (nodeDef.type === NodeType.Directive || nodeDef.type === NodeType.Element) {
|
||||
const bindingValues: {[key: string]: string} = {};
|
||||
for (let i = 0; i < nodeDef.bindings.length; i++) {
|
||||
|
@ -206,8 +230,7 @@ function debugCheckFn(
|
|||
const value = values[i];
|
||||
if ((binding.type === BindingType.ElementProperty ||
|
||||
binding.type === BindingType.ComponentHostProperty ||
|
||||
binding.type === BindingType.DirectiveProperty) &&
|
||||
checkBinding(view, nodeDef, i, value)) {
|
||||
binding.type === BindingType.DirectiveProperty)) {
|
||||
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] =
|
||||
normalizeDebugBindingValue(value);
|
||||
}
|
||||
|
@ -225,8 +248,12 @@ function debugCheckFn(
|
|||
}
|
||||
}
|
||||
}
|
||||
return (<any>delegate)(view, nodeIndex, argStyle, ...givenValues);
|
||||
};
|
||||
}
|
||||
|
||||
function debugCheckNoChangesNode(
|
||||
view: ViewData, nodeDef: NodeDef, argStyle: ArgumentType, values: any[]): void {
|
||||
(<any>checkNoChangesNode)(view, nodeDef, argStyle, ...values);
|
||||
}
|
||||
|
||||
function normalizeDebugBindingName(name: string) {
|
||||
// Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
|
||||
|
|
|
@ -66,7 +66,7 @@ export function createText(view: ViewData, renderHost: any, def: NodeDef): TextD
|
|||
|
||||
export function checkAndUpdateTextInline(
|
||||
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any, v8: any, v9: any) {
|
||||
v7: any, v8: any, v9: any): boolean {
|
||||
let changed = false;
|
||||
const bindings = def.bindings;
|
||||
const bindLen = bindings.length;
|
||||
|
@ -96,9 +96,10 @@ export function checkAndUpdateTextInline(
|
|||
const renderNode = asTextData(view, def.index).renderText;
|
||||
view.renderer.setValue(renderNode, value);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values: any[]) {
|
||||
export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values: any[]): boolean {
|
||||
const bindings = def.bindings;
|
||||
let changed = false;
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
|
@ -117,6 +118,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values:
|
|||
const renderNode = asTextData(view, def.index).renderText;
|
||||
view.renderer.setValue(renderNode, value);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function _addInterpolationPart(value: any, binding: BindingDef): string {
|
||||
|
|
|
@ -312,6 +312,7 @@ export interface ViewData {
|
|||
// index of component provider / anchor.
|
||||
parentNodeDef: NodeDef;
|
||||
parent: ViewData;
|
||||
viewContainerParent: ViewData;
|
||||
component: any;
|
||||
context: any;
|
||||
// Attention: Never loop over this, as this will
|
||||
|
@ -448,6 +449,11 @@ export abstract class DebugContext {
|
|||
// Other
|
||||
// -------------------------------------
|
||||
|
||||
export enum CheckType {
|
||||
CheckAndUpdate,
|
||||
CheckNoChanges
|
||||
}
|
||||
|
||||
export interface Services {
|
||||
setCurrentNode(view: ViewData, nodeIndex: number): void;
|
||||
createRootView(
|
||||
|
@ -456,17 +462,15 @@ export interface Services {
|
|||
createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData;
|
||||
checkAndUpdateView(view: ViewData): void;
|
||||
checkNoChangesView(view: ViewData): void;
|
||||
attachEmbeddedView(elementData: ElementData, viewIndex: number, view: ViewData): void;
|
||||
detachEmbeddedView(elementData: ElementData, viewIndex: number): ViewData;
|
||||
moveEmbeddedView(elementData: ElementData, oldViewIndex: number, newViewIndex: number): ViewData;
|
||||
destroyView(view: ViewData): void;
|
||||
resolveDep(
|
||||
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
|
||||
notFoundValue?: any): any;
|
||||
createDebugContext(view: ViewData, nodeIndex: number): DebugContext;
|
||||
handleEvent: ViewHandleEventFn;
|
||||
updateDirectives: ViewUpdateFn;
|
||||
updateRenderer: ViewUpdateFn;
|
||||
updateDirectives: (view: ViewData, checkType: CheckType) => void;
|
||||
updateRenderer: (view: ViewData, checkType: CheckType) => void;
|
||||
dirtyParentQueries: (view: ViewData) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -480,12 +484,10 @@ export const Services: Services = {
|
|||
checkAndUpdateView: undefined,
|
||||
checkNoChangesView: undefined,
|
||||
destroyView: undefined,
|
||||
attachEmbeddedView: undefined,
|
||||
detachEmbeddedView: undefined,
|
||||
moveEmbeddedView: undefined,
|
||||
resolveDep: undefined,
|
||||
createDebugContext: undefined,
|
||||
handleEvent: undefined,
|
||||
updateDirectives: undefined,
|
||||
updateRenderer: undefined,
|
||||
dirtyParentQueries: undefined,
|
||||
};
|
||||
|
|
|
@ -60,9 +60,22 @@ export function createRendererTypeV2(values: {
|
|||
|
||||
export function checkBinding(
|
||||
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
|
||||
const oldValue = view.oldValues[def.bindingIndex + bindingIdx];
|
||||
return unwrapCounter > 0 || !!(view.state & ViewState.FirstCheck) ||
|
||||
!devModeEqual(oldValue, value);
|
||||
const oldValues = view.oldValues;
|
||||
if (unwrapCounter > 0 || !!(view.state & ViewState.FirstCheck) ||
|
||||
!looseIdentical(oldValues[def.bindingIndex + bindingIdx], value)) {
|
||||
unwrapCounter = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkAndUpdateBinding(
|
||||
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
|
||||
if (checkBinding(view, def, bindingIdx, value)) {
|
||||
view.oldValues[def.bindingIndex + bindingIdx] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkBindingNoChanges(
|
||||
|
@ -76,27 +89,19 @@ export function checkBindingNoChanges(
|
|||
}
|
||||
}
|
||||
|
||||
export function checkAndUpdateBinding(
|
||||
view: ViewData, def: NodeDef, bindingIdx: number, value: any): boolean {
|
||||
const oldValues = view.oldValues;
|
||||
if (unwrapCounter || (view.state & ViewState.FirstCheck) ||
|
||||
!looseIdentical(oldValues[def.bindingIndex + bindingIdx], value)) {
|
||||
unwrapCounter = 0;
|
||||
oldValues[def.bindingIndex + bindingIdx] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function dispatchEvent(
|
||||
view: ViewData, nodeIndex: number, eventName: string, event: any): boolean {
|
||||
export function markParentViewsForCheck(view: ViewData) {
|
||||
let currView = view;
|
||||
while (currView) {
|
||||
if (currView.def.flags & ViewFlags.OnPush) {
|
||||
currView.state |= ViewState.ChecksEnabled;
|
||||
}
|
||||
currView = currView.parent;
|
||||
currView = currView.viewContainerParent || currView.parent;
|
||||
}
|
||||
}
|
||||
|
||||
export function dispatchEvent(
|
||||
view: ViewData, nodeIndex: number, eventName: string, event: any): boolean {
|
||||
markParentViewsForCheck(view);
|
||||
return Services.handleEvent(view, nodeIndex, eventName, event);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import {callLifecycleHooksChildrenFirst, checkAndUpdateDirectiveDynamic, checkAn
|
|||
import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, createPureExpression} from './pure_expression';
|
||||
import {checkAndUpdateQuery, createQuery, queryDef} from './query';
|
||||
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
|
||||
import {ArgumentType, ElementData, ElementDef, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderDef, RootData, Services, TextDef, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asProviderData, asPureExpressionData, asQueryList, asTextData} from './types';
|
||||
import {ArgumentType, CheckType, ElementData, ElementDef, NodeData, NodeDef, NodeFlags, NodeType, ProviderData, ProviderDef, RootData, Services, TextDef, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asProviderData, asPureExpressionData, asQueryList, asTextData} from './types';
|
||||
import {checkBindingNoChanges, isComponentView, resolveViewDefinition, viewParentEl} from './util';
|
||||
|
||||
const NOOP = (): any => undefined;
|
||||
|
@ -246,7 +246,7 @@ function createView(
|
|||
const view: ViewData = {
|
||||
def,
|
||||
parent,
|
||||
parentNodeDef,
|
||||
viewContainerParent: undefined, parentNodeDef,
|
||||
context: undefined,
|
||||
component: undefined, nodes,
|
||||
state: ViewState.FirstCheck | ViewState.ChecksEnabled, root, renderer,
|
||||
|
@ -339,35 +339,35 @@ function createViewNodes(view: ViewData) {
|
|||
// fill static content and view queries
|
||||
execQueriesAction(
|
||||
view, NodeFlags.HasContentQuery | NodeFlags.HasViewQuery, NodeFlags.HasStaticQuery,
|
||||
QueryAction.CheckAndUpdate);
|
||||
CheckType.CheckAndUpdate);
|
||||
}
|
||||
|
||||
export function checkNoChangesView(view: ViewData) {
|
||||
Services.updateDirectives(checkNoChangesNode, view);
|
||||
Services.updateDirectives(view, CheckType.CheckNoChanges);
|
||||
execEmbeddedViewsAction(view, ViewAction.CheckNoChanges);
|
||||
execQueriesAction(
|
||||
view, NodeFlags.HasContentQuery, NodeFlags.HasDynamicQuery, QueryAction.CheckNoChanges);
|
||||
Services.updateRenderer(checkNoChangesNode, view);
|
||||
view, NodeFlags.HasContentQuery, NodeFlags.HasDynamicQuery, CheckType.CheckNoChanges);
|
||||
Services.updateRenderer(view, CheckType.CheckNoChanges);
|
||||
execComponentViewsAction(view, ViewAction.CheckNoChanges);
|
||||
execQueriesAction(
|
||||
view, NodeFlags.HasViewQuery, NodeFlags.HasDynamicQuery, QueryAction.CheckNoChanges);
|
||||
view, NodeFlags.HasViewQuery, NodeFlags.HasDynamicQuery, CheckType.CheckNoChanges);
|
||||
}
|
||||
|
||||
export function checkAndUpdateView(view: ViewData) {
|
||||
Services.updateDirectives(checkAndUpdateNode, view);
|
||||
Services.updateDirectives(view, CheckType.CheckAndUpdate);
|
||||
execEmbeddedViewsAction(view, ViewAction.CheckAndUpdate);
|
||||
execQueriesAction(
|
||||
view, NodeFlags.HasContentQuery, NodeFlags.HasDynamicQuery, QueryAction.CheckAndUpdate);
|
||||
view, NodeFlags.HasContentQuery, NodeFlags.HasDynamicQuery, CheckType.CheckAndUpdate);
|
||||
|
||||
callLifecycleHooksChildrenFirst(
|
||||
view, NodeFlags.AfterContentChecked |
|
||||
(view.state & ViewState.FirstCheck ? NodeFlags.AfterContentInit : 0));
|
||||
|
||||
Services.updateRenderer(checkAndUpdateNode, view);
|
||||
Services.updateRenderer(view, CheckType.CheckAndUpdate);
|
||||
|
||||
execComponentViewsAction(view, ViewAction.CheckAndUpdate);
|
||||
execQueriesAction(
|
||||
view, NodeFlags.HasViewQuery, NodeFlags.HasDynamicQuery, QueryAction.CheckAndUpdate);
|
||||
view, NodeFlags.HasViewQuery, NodeFlags.HasDynamicQuery, CheckType.CheckAndUpdate);
|
||||
|
||||
callLifecycleHooksChildrenFirst(
|
||||
view, NodeFlags.AfterViewChecked |
|
||||
|
@ -379,61 +379,83 @@ export function checkAndUpdateView(view: ViewData) {
|
|||
view.state &= ~ViewState.FirstCheck;
|
||||
}
|
||||
|
||||
function checkAndUpdateNode(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any {
|
||||
export function checkAndUpdateNode(
|
||||
view: ViewData, nodeDef: NodeDef, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): boolean {
|
||||
if (argStyle === ArgumentType.Inline) {
|
||||
return checkAndUpdateNodeInline(view, nodeIndex, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
return checkAndUpdateNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
} else {
|
||||
return checkAndUpdateNodeDynamic(view, nodeIndex, v0);
|
||||
return checkAndUpdateNodeDynamic(view, nodeDef, v0);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAndUpdateNodeInline(
|
||||
view: ViewData, nodeIndex: number, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any,
|
||||
v6?: any, v7?: any, v8?: any, v9?: any): any {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
view: ViewData, nodeDef: NodeDef, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any,
|
||||
v6?: any, v7?: any, v8?: any, v9?: any): boolean {
|
||||
let changed = false;
|
||||
switch (nodeDef.type) {
|
||||
case NodeType.Element:
|
||||
return checkAndUpdateElementInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
changed = checkAndUpdateElementInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
break;
|
||||
case NodeType.Text:
|
||||
return checkAndUpdateTextInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
changed = checkAndUpdateTextInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
break;
|
||||
case NodeType.Directive:
|
||||
return checkAndUpdateDirectiveInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
changed =
|
||||
checkAndUpdateDirectiveInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
break;
|
||||
case NodeType.PureExpression:
|
||||
return checkAndUpdatePureExpressionInline(
|
||||
view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
changed =
|
||||
checkAndUpdatePureExpressionInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
break;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function checkAndUpdateNodeDynamic(view: ViewData, nodeIndex: number, values: any[]): any {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
function checkAndUpdateNodeDynamic(view: ViewData, nodeDef: NodeDef, values: any[]): boolean {
|
||||
let changed = false;
|
||||
switch (nodeDef.type) {
|
||||
case NodeType.Element:
|
||||
return checkAndUpdateElementDynamic(view, nodeDef, values);
|
||||
changed = checkAndUpdateElementDynamic(view, nodeDef, values);
|
||||
break;
|
||||
case NodeType.Text:
|
||||
return checkAndUpdateTextDynamic(view, nodeDef, values);
|
||||
changed = checkAndUpdateTextDynamic(view, nodeDef, values);
|
||||
break;
|
||||
case NodeType.Directive:
|
||||
return checkAndUpdateDirectiveDynamic(view, nodeDef, values);
|
||||
changed = checkAndUpdateDirectiveDynamic(view, nodeDef, values);
|
||||
break;
|
||||
case NodeType.PureExpression:
|
||||
return checkAndUpdatePureExpressionDynamic(view, nodeDef, values);
|
||||
changed = checkAndUpdatePureExpressionDynamic(view, nodeDef, values);
|
||||
break;
|
||||
}
|
||||
if (changed) {
|
||||
// Update oldValues after all bindings have been updated,
|
||||
// as a setter for a property might update other properties.
|
||||
const bindLen = nodeDef.bindings.length;
|
||||
const bindingStart = nodeDef.bindingIndex;
|
||||
const oldValues = view.oldValues;
|
||||
for (let i = 0; i < bindLen; i++) {
|
||||
oldValues[bindingStart + i] = values[i];
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
function checkNoChangesNode(
|
||||
view: ViewData, nodeIndex: number, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
export function checkNoChangesNode(
|
||||
view: ViewData, nodeDef: NodeDef, argStyle: ArgumentType, v0?: any, v1?: any, v2?: any,
|
||||
v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any {
|
||||
if (argStyle === ArgumentType.Inline) {
|
||||
return checkNoChangesNodeInline(view, nodeIndex, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
checkNoChangesNodeInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
} else {
|
||||
return checkNoChangesNodeDynamic(view, nodeIndex, v0);
|
||||
checkNoChangesNodeDynamic(view, nodeDef, v0);
|
||||
}
|
||||
// Returning false is ok here as we would have thrown in case of a change.
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkNoChangesNodeInline(
|
||||
view: ViewData, nodeIndex: number, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
|
||||
v6: any, v7: any, v8: any, v9: any): void {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
view: ViewData, nodeDef: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
|
||||
v7: any, v8: any, v9: any): void {
|
||||
const bindLen = nodeDef.bindings.length;
|
||||
if (bindLen > 0) checkBindingNoChanges(view, nodeDef, 0, v0);
|
||||
if (bindLen > 1) checkBindingNoChanges(view, nodeDef, 1, v1);
|
||||
|
@ -445,17 +467,12 @@ function checkNoChangesNodeInline(
|
|||
if (bindLen > 7) checkBindingNoChanges(view, nodeDef, 7, v7);
|
||||
if (bindLen > 8) checkBindingNoChanges(view, nodeDef, 8, v8);
|
||||
if (bindLen > 9) checkBindingNoChanges(view, nodeDef, 9, v9);
|
||||
return nodeDef.type === NodeType.PureExpression ? asPureExpressionData(view, nodeIndex).value :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function checkNoChangesNodeDynamic(view: ViewData, nodeIndex: number, values: any[]): void {
|
||||
const nodeDef = view.def.nodes[nodeIndex];
|
||||
function checkNoChangesNodeDynamic(view: ViewData, nodeDef: NodeDef, values: any[]): void {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
checkBindingNoChanges(view, nodeDef, i, values[i]);
|
||||
}
|
||||
return nodeDef.type === NodeType.PureExpression ? asPureExpressionData(view, nodeIndex).value :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function checkNoChangesQuery(view: ViewData, nodeDef: NodeDef) {
|
||||
|
@ -574,13 +591,9 @@ function callViewAction(view: ViewData, action: ViewAction) {
|
|||
}
|
||||
}
|
||||
|
||||
enum QueryAction {
|
||||
CheckAndUpdate,
|
||||
CheckNoChanges
|
||||
}
|
||||
|
||||
function execQueriesAction(
|
||||
view: ViewData, queryFlags: NodeFlags, staticDynamicQueryFlag: NodeFlags, action: QueryAction) {
|
||||
view: ViewData, queryFlags: NodeFlags, staticDynamicQueryFlag: NodeFlags,
|
||||
checkType: CheckType) {
|
||||
if (!(view.def.nodeFlags & queryFlags) || !(view.def.nodeFlags & staticDynamicQueryFlag)) {
|
||||
return;
|
||||
}
|
||||
|
@ -589,11 +602,11 @@ function execQueriesAction(
|
|||
const nodeDef = view.def.nodes[i];
|
||||
if ((nodeDef.flags & queryFlags) && (nodeDef.flags & staticDynamicQueryFlag)) {
|
||||
Services.setCurrentNode(view, nodeDef.index);
|
||||
switch (action) {
|
||||
case QueryAction.CheckAndUpdate:
|
||||
switch (checkType) {
|
||||
case CheckType.CheckAndUpdate:
|
||||
checkAndUpdateQuery(view, nodeDef);
|
||||
break;
|
||||
case QueryAction.CheckNoChanges:
|
||||
case CheckType.CheckNoChanges:
|
||||
checkNoChangesQuery(view, nodeDef);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {dirtyParentQueries} from './query';
|
||||
import {ElementData, NodeData, NodeDef, NodeFlags, NodeType, ViewData, asElementData, asProviderData, asTextData} from './types';
|
||||
import {ElementData, NodeData, NodeDef, NodeFlags, NodeType, Services, ViewData, asElementData, asProviderData, asTextData} from './types';
|
||||
import {RenderNodeAction, declaredViewContainer, isComponentView, renderNode, rootRenderNodes, visitProjectedRenderNodes, visitRootRenderNodes} from './util';
|
||||
|
||||
export function attachEmbeddedView(elementData: ElementData, viewIndex: number, view: ViewData) {
|
||||
export function attachEmbeddedView(
|
||||
parentView: ViewData, elementData: ElementData, viewIndex: number, view: ViewData) {
|
||||
let embeddedViews = elementData.embeddedViews;
|
||||
if (viewIndex == null) {
|
||||
viewIndex = embeddedViews.length;
|
||||
}
|
||||
view.viewContainerParent = parentView;
|
||||
addToArray(embeddedViews, viewIndex, view);
|
||||
const dvcElementData = declaredViewContainer(view);
|
||||
if (dvcElementData && dvcElementData !== elementData) {
|
||||
|
@ -25,7 +26,7 @@ export function attachEmbeddedView(elementData: ElementData, viewIndex: number,
|
|||
projectedViews.push(view);
|
||||
}
|
||||
|
||||
dirtyParentQueries(view);
|
||||
Services.dirtyParentQueries(view);
|
||||
|
||||
const prevView = viewIndex > 0 ? embeddedViews[viewIndex - 1] : null;
|
||||
renderAttachEmbeddedView(elementData, prevView, view);
|
||||
|
@ -40,6 +41,7 @@ export function detachEmbeddedView(elementData: ElementData, viewIndex: number):
|
|||
return null;
|
||||
}
|
||||
const view = embeddedViews[viewIndex];
|
||||
view.viewContainerParent = undefined;
|
||||
removeFromArray(embeddedViews, viewIndex);
|
||||
|
||||
const dvcElementData = declaredViewContainer(view);
|
||||
|
@ -48,9 +50,9 @@ export function detachEmbeddedView(elementData: ElementData, viewIndex: number):
|
|||
removeFromArray(projectedViews, projectedViews.indexOf(view));
|
||||
}
|
||||
|
||||
dirtyParentQueries(view);
|
||||
Services.dirtyParentQueries(view);
|
||||
|
||||
renderDetachEmbeddedView(elementData, view);
|
||||
renderDetachView(view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -68,9 +70,9 @@ export function moveEmbeddedView(
|
|||
// Note: Don't need to change projectedViews as the order in there
|
||||
// as always invalid...
|
||||
|
||||
dirtyParentQueries(view);
|
||||
Services.dirtyParentQueries(view);
|
||||
|
||||
renderDetachEmbeddedView(elementData, view);
|
||||
renderDetachView(view);
|
||||
const prevView = newViewIndex > 0 ? embeddedViews[newViewIndex - 1] : null;
|
||||
renderAttachEmbeddedView(elementData, prevView, view);
|
||||
|
||||
|
@ -87,9 +89,8 @@ function renderAttachEmbeddedView(elementData: ElementData, prevView: ViewData,
|
|||
visitRootRenderNodes(view, RenderNodeAction.InsertBefore, parentNode, nextSibling, undefined);
|
||||
}
|
||||
|
||||
function renderDetachEmbeddedView(elementData: ElementData, view: ViewData) {
|
||||
const parentNode = view.renderer.parentNode(elementData.renderElement);
|
||||
visitRootRenderNodes(view, RenderNodeAction.RemoveChild, parentNode, null, undefined);
|
||||
export function renderDetachView(view: ViewData) {
|
||||
visitRootRenderNodes(view, RenderNodeAction.RemoveChild, null, null, undefined);
|
||||
}
|
||||
|
||||
function addToArray(arr: any[], index: number, value: any) {
|
||||
|
|
|
@ -78,7 +78,7 @@ export function main() {
|
|||
it('should throw when reentering tick', inject([ApplicationRef], (ref: ApplicationRef_) => {
|
||||
const view = jasmine.createSpyObj('view', ['detach', 'attachToAppRef']);
|
||||
const viewRef = jasmine.createSpyObj(
|
||||
'viewRef', ['detectChanges', 'detachFromContainer', 'attachToAppRef']);
|
||||
'viewRef', ['detectChanges', 'detachFromAppRef', 'attachToAppRef']);
|
||||
viewRef.internalView = view;
|
||||
view.ref = viewRef;
|
||||
try {
|
||||
|
|
|
@ -66,8 +66,8 @@ export function main() {
|
|||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
const childView1 = Services.createEmbeddedView(parentView, parentView.def.nodes[2]);
|
||||
|
||||
attachEmbeddedView(viewContainerData, 0, childView0);
|
||||
attachEmbeddedView(viewContainerData, 1, childView1);
|
||||
attachEmbeddedView(parentView, viewContainerData, 0, childView0);
|
||||
attachEmbeddedView(parentView, viewContainerData, 1, childView1);
|
||||
|
||||
// 2 anchors + 2 elements
|
||||
const rootChildren = getDOM().childNodes(rootNodes[0]);
|
||||
|
@ -96,8 +96,8 @@ export function main() {
|
|||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
const childView1 = Services.createEmbeddedView(parentView, parentView.def.nodes[2]);
|
||||
|
||||
attachEmbeddedView(viewContainerData, 0, childView0);
|
||||
attachEmbeddedView(viewContainerData, 1, childView1);
|
||||
attachEmbeddedView(parentView, viewContainerData, 0, childView0);
|
||||
attachEmbeddedView(parentView, viewContainerData, 1, childView1);
|
||||
|
||||
moveEmbeddedView(viewContainerData, 0, 1);
|
||||
|
||||
|
@ -118,7 +118,7 @@ export function main() {
|
|||
]));
|
||||
|
||||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[0]);
|
||||
attachEmbeddedView(asElementData(parentView, 0), 0, childView0);
|
||||
attachEmbeddedView(parentView, asElementData(parentView, 0), 0, childView0);
|
||||
|
||||
const rootNodes = rootRenderNodes(parentView);
|
||||
expect(rootNodes.length).toBe(3);
|
||||
|
@ -146,7 +146,7 @@ export function main() {
|
|||
|
||||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
|
||||
attachEmbeddedView(asElementData(parentView, 1), 0, childView0);
|
||||
attachEmbeddedView(parentView, asElementData(parentView, 1), 0, childView0);
|
||||
|
||||
Services.checkAndUpdateView(parentView);
|
||||
|
||||
|
@ -180,7 +180,7 @@ export function main() {
|
|||
|
||||
const childView0 = Services.createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
|
||||
attachEmbeddedView(asElementData(parentView, 1), 0, childView0);
|
||||
attachEmbeddedView(parentView, asElementData(parentView, 1), 0, childView0);
|
||||
Services.destroyView(parentView);
|
||||
|
||||
expect(log).toEqual(['ngOnDestroy']);
|
||||
|
|
|
@ -114,7 +114,7 @@ export function main() {
|
|||
const componentView = asElementData(view, 0).componentView;
|
||||
const view0 = Services.createEmbeddedView(componentView, componentView.def.nodes[1]);
|
||||
|
||||
attachEmbeddedView(asElementData(componentView, 1), 0, view0);
|
||||
attachEmbeddedView(view, asElementData(componentView, 1), 0, view0);
|
||||
expect(getDOM().childNodes(getDOM().firstChild(rootNodes[0])).length).toBe(3);
|
||||
expect(getDOM().childNodes(getDOM().firstChild(rootNodes[0]))[1])
|
||||
.toBe(asTextData(view, 2).renderText);
|
||||
|
|
|
@ -156,7 +156,7 @@ export function main() {
|
|||
]));
|
||||
|
||||
const childView = Services.createEmbeddedView(view, view.def.nodes[3]);
|
||||
attachEmbeddedView(asElementData(view, 3), 0, childView);
|
||||
attachEmbeddedView(view, asElementData(view, 3), 0, childView);
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
// queries on parent elements of anchors
|
||||
|
@ -185,7 +185,7 @@ export function main() {
|
|||
|
||||
const childView = Services.createEmbeddedView(view, view.def.nodes[3]);
|
||||
// attach at a different place than the one where the template was defined
|
||||
attachEmbeddedView(asElementData(view, 7), 0, childView);
|
||||
attachEmbeddedView(view, asElementData(view, 7), 0, childView);
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
|
@ -215,12 +215,13 @@ export function main() {
|
|||
expect(qs.a.length).toBe(0);
|
||||
|
||||
const childView = Services.createEmbeddedView(view, view.def.nodes[3]);
|
||||
attachEmbeddedView(asElementData(view, 3), 0, childView);
|
||||
attachEmbeddedView(view, asElementData(view, 3), 0, childView);
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
expect(qs.a.length).toBe(1);
|
||||
|
||||
detachEmbeddedView(asElementData(view, 3), 0);
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
expect(qs.a.length).toBe(0);
|
||||
|
@ -245,7 +246,7 @@ export function main() {
|
|||
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
const childView = Services.createEmbeddedView(compView, compView.def.nodes[1]);
|
||||
attachEmbeddedView(asElementData(compView, 1), 0, childView);
|
||||
attachEmbeddedView(view, asElementData(compView, 1), 0, childView);
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
expect(comp.a.length).toBe(1);
|
||||
|
@ -381,7 +382,7 @@ export function main() {
|
|||
Services.checkNoChangesView(view);
|
||||
|
||||
const childView = Services.createEmbeddedView(view, view.def.nodes[3]);
|
||||
attachEmbeddedView(asElementData(view, 3), 0, childView);
|
||||
attachEmbeddedView(view, asElementData(view, 3), 0, childView);
|
||||
|
||||
let err: any;
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue