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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user