From f42382db3b9218fd0f1f14766ebfc271c52c8b42 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Fri, 17 Jul 2015 08:03:40 -0700 Subject: [PATCH] refactor(views): split `ViewManager/ViewContainerRef.createView` into 2 methods BREAKING CHANGES: `ViewManager.createView` / `ViewContainerRef.create` have been split into 2 methods: - `createHostView` which takes dynamically created bindings - `createEmbeddedView` which takes the newly introduced `TemplateRef` The new type `TemplateRef` is the combination of a `ProtoViewRef` and and `ElementRef` from the same place. Use `TemplateRef` when working with embedded views in `ng-if`, `ng-for`, ... instead of `ProtoViewRef`. Also, `ProtoViewRef` is no more injectable, but `TemplateRef` is. First part of #1989 to clean up manual content projection. Closes #3114 --- modules/angular2/core.ts | 1 + .../src/core/annotations_impl/annotations.ts | 8 +-- .../angular2/src/core/compiler/compiler.ts | 4 +- .../core/compiler/dynamic_component_loader.ts | 2 +- .../src/core/compiler/element_injector.ts | 14 ++--- .../src/core/compiler/template_ref.ts | 32 +++++++++++ modules/angular2/src/core/compiler/view.ts | 4 +- .../src/core/compiler/view_container_ref.ts | 14 +++-- .../src/core/compiler/view_manager.ts | 57 +++++++++++++------ .../src/core/compiler/view_manager_utils.ts | 11 ++-- modules/angular2/src/directives/ng_for.ts | 10 ++-- modules/angular2/src/directives/ng_if.ts | 10 ++-- modules/angular2/src/directives/ng_switch.ts | 18 +++--- .../core/compiler/element_injector_spec.ts | 46 +++++++-------- .../test/core/compiler/integration_spec.ts | 26 ++++----- .../compiler/projection_integration_spec.ts | 19 +++---- .../test/core/compiler/view_manager_spec.ts | 48 +++++++++------- 17 files changed, 198 insertions(+), 126 deletions(-) create mode 100644 modules/angular2/src/core/compiler/template_ref.ts diff --git a/modules/angular2/core.ts b/modules/angular2/core.ts index db45babf23..896d674a91 100644 --- a/modules/angular2/core.ts +++ b/modules/angular2/core.ts @@ -18,6 +18,7 @@ export {AppViewManager} from 'angular2/src/core/compiler/view_manager'; export {IQueryList} from 'angular2/src/core/compiler/interface_query'; export {QueryList} from 'angular2/src/core/compiler/query_list'; export {ElementRef} from 'angular2/src/core/compiler/element_ref'; +export {TemplateRef} from 'angular2/src/core/compiler/template_ref'; export {RenderElementRef} from 'angular2/src/render/api'; export {ViewRef, ProtoViewRef} from 'angular2/src/core/compiler/view_ref'; export {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; diff --git a/modules/angular2/src/core/annotations_impl/annotations.ts b/modules/angular2/src/core/annotations_impl/annotations.ts index ab45048618..1a96cbf085 100644 --- a/modules/angular2/src/core/annotations_impl/annotations.ts +++ b/modules/angular2/src/core/annotations_impl/annotations.ts @@ -360,12 +360,12 @@ import {DEFAULT} from 'angular2/change_detection'; * }) * export class Unless { * viewContainer: ViewContainerRef; - * protoViewRef: ProtoViewRef; + * templateRef: TemplateRef; * prevCondition: boolean; * - * constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) { + * constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef) { * this.viewContainer = viewContainer; - * this.protoViewRef = protoViewRef; + * this.templateRef = templateRef; * this.prevCondition = null; * } * @@ -375,7 +375,7 @@ import {DEFAULT} from 'angular2/change_detection'; * this.viewContainer.clear(); * } else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) { * this.prevCondition = false; - * this.viewContainer.create(this.protoViewRef); + * this.viewContainer.create(this.templateRef); * } * } * } diff --git a/modules/angular2/src/core/compiler/compiler.ts b/modules/angular2/src/core/compiler/compiler.ts index eeccfa6900..c03e0a9c31 100644 --- a/modules/angular2/src/core/compiler/compiler.ts +++ b/modules/angular2/src/core/compiler/compiler.ts @@ -146,8 +146,8 @@ export class Compiler { return this._compileNestedProtoViews(hostRenderPv, protoView, componentType); }); } - return hostPvPromise.then(hostAppProtoView => this._mergeCyclicEmbeddedProtoViews().then( - _ => new ProtoViewRef(hostAppProtoView))); + return hostPvPromise.then( + hostAppProtoView => this._mergeCyclicEmbeddedProtoViews().then(_ => hostAppProtoView.ref)); } private _compile(componentBinding: DirectiveBinding): Promise| AppProtoView { diff --git a/modules/angular2/src/core/compiler/dynamic_component_loader.ts b/modules/angular2/src/core/compiler/dynamic_component_loader.ts index c1317d2ff2..b464becab1 100644 --- a/modules/angular2/src/core/compiler/dynamic_component_loader.ts +++ b/modules/angular2/src/core/compiler/dynamic_component_loader.ts @@ -63,7 +63,7 @@ export class DynamicComponentLoader { .then(hostProtoViewRef => { var viewContainer = this._viewManager.getViewContainer(location); var hostViewRef = - viewContainer.create(hostProtoViewRef, viewContainer.length, null, bindings); + viewContainer.createHostView(hostProtoViewRef, viewContainer.length, bindings); var newLocation = this._viewManager.getHostElement(hostViewRef); var component = this._viewManager.getComponent(newLocation); diff --git a/modules/angular2/src/core/compiler/element_injector.ts b/modules/angular2/src/core/compiler/element_injector.ts index 5c41fc0267..043f05fbfe 100644 --- a/modules/angular2/src/core/compiler/element_injector.ts +++ b/modules/angular2/src/core/compiler/element_injector.ts @@ -40,7 +40,7 @@ import * as viewModule from './view'; import * as avmModule from './view_manager'; import {ViewContainerRef} from './view_container_ref'; import {ElementRef} from './element_ref'; -import {ProtoViewRef, ViewRef} from './view_ref'; +import {TemplateRef} from './template_ref'; import {Directive, Component, LifecycleEvent} from 'angular2/src/core/annotations_impl/annotations'; import {hasLifecycleHook} from './directive_lifecycle_reflector'; import {ChangeDetector, ChangeDetectorRef, Pipes} from 'angular2/change_detection'; @@ -52,7 +52,7 @@ var _staticKeys; export class StaticKeys { viewManagerId: number; - protoViewId: number; + templateRefId: number; viewContainerId: number; changeDetectorRefId: number; elementRefId: number; @@ -60,7 +60,7 @@ export class StaticKeys { constructor() { this.viewManagerId = Key.get(avmModule.AppViewManager).id; - this.protoViewId = Key.get(ProtoViewRef).id; + this.templateRefId = Key.get(TemplateRef).id; this.viewContainerId = Key.get(ViewContainerRef).id; this.changeDetectorRefId = Key.get(ChangeDetectorRef).id; this.elementRefId = Key.get(ElementRef).id; @@ -278,7 +278,7 @@ export class DirectiveBinding extends ResolvedBinding { // TODO(rado): benchmark and consider rolling in as ElementInjector fields. export class PreBuiltObjects { constructor(public viewManager: avmModule.AppViewManager, public view: viewModule.AppView, - public elementRef: ElementRef, public protoView: viewModule.AppProtoView) {} + public elementRef: ElementRef, public templateRef: TemplateRef) {} } export class EventEmitterAccessor { @@ -622,15 +622,15 @@ export class ElementInjector extends TreeNode implements Depend return this.getViewContainerRef(); } - if (dirDep.key.id === StaticKeys.instance().protoViewId) { - if (isBlank(this._preBuiltObjects.protoView)) { + if (dirDep.key.id === StaticKeys.instance().templateRefId) { + if (isBlank(this._preBuiltObjects.templateRef)) { if (dirDep.optional) { return null; } throw new NoBindingError(dirDep.key); } - return new ProtoViewRef(this._preBuiltObjects.protoView); + return this._preBuiltObjects.templateRef; } return undefinedValue; diff --git a/modules/angular2/src/core/compiler/template_ref.ts b/modules/angular2/src/core/compiler/template_ref.ts new file mode 100644 index 0000000000..d654b50765 --- /dev/null +++ b/modules/angular2/src/core/compiler/template_ref.ts @@ -0,0 +1,32 @@ +import {internalView, ProtoViewRef} from './view_ref'; +import {ElementRef} from './element_ref'; +import * as viewModule from './view'; + +/** + * Reference to a template within a component. + * + * Represents an opaque reference to the underlying template that can + * be instantiated using the {@Link ViewContainerRef}. + */ +export class TemplateRef { + /** + * The location of the template + */ + elementRef: ElementRef; + + constructor(elementRef: ElementRef) { this.elementRef = elementRef; } + + private _getProtoView(): viewModule.AppProtoView { + var parentView = internalView(this.elementRef.parentView); + return parentView.proto + .elementBinders[this.elementRef.boundElementIndex - parentView.elementOffset] + .nestedProtoView; + } + + get protoViewRef(): ProtoViewRef { return this._getProtoView().ref; } + + /** + * Whether this template has a local variable with the given name + */ + hasLocal(name: string): boolean { return this._getProtoView().protoLocals.has(name); } +} diff --git a/modules/angular2/src/core/compiler/view.ts b/modules/angular2/src/core/compiler/view.ts index 6390b55634..82912cb0bf 100644 --- a/modules/angular2/src/core/compiler/view.ts +++ b/modules/angular2/src/core/compiler/view.ts @@ -21,7 +21,7 @@ import {ElementBinder} from './element_binder'; import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; import * as renderApi from 'angular2/src/render/api'; import {RenderEventDispatcher} from 'angular2/src/render/api'; -import {ViewRef, internalView} from './view_ref'; +import {ViewRef, ProtoViewRef, internalView} from './view_ref'; import {ElementRef} from './element_ref'; export class AppProtoViewMergeMapping { @@ -256,10 +256,12 @@ export class AppProtoView { elementBinders: List = []; protoLocals: Map = new Map(); mergeMapping: AppProtoViewMergeMapping; + ref: ProtoViewRef; constructor(public type: renderApi.ViewType, public protoChangeDetector: ProtoChangeDetector, public variableBindings: Map, public variableLocations: Map, public textBindingCount: number) { + this.ref = new ProtoViewRef(this); if (isPresent(variableBindings)) { MapWrapper.forEach(variableBindings, (templateName, _) => { this.protoLocals.set(templateName, null); }); diff --git a/modules/angular2/src/core/compiler/view_container_ref.ts b/modules/angular2/src/core/compiler/view_container_ref.ts index d65947021c..6f32de4d0e 100644 --- a/modules/angular2/src/core/compiler/view_container_ref.ts +++ b/modules/angular2/src/core/compiler/view_container_ref.ts @@ -6,6 +6,7 @@ import * as avmModule from './view_manager'; import * as viewModule from './view'; import {ElementRef} from './element_ref'; +import {TemplateRef} from './template_ref'; import {ViewRef, ProtoViewRef, internalView} from './view_ref'; export class ViewContainerRef { @@ -28,11 +29,16 @@ export class ViewContainerRef { // TODO(rado): profile and decide whether bounds checks should be added // to the methods below. - create(protoViewRef: ProtoViewRef = null, atIndex: number = -1, context: ElementRef = null, - bindings: ResolvedBinding[] = null): ViewRef { + createEmbeddedView(templateRef: TemplateRef, atIndex: number = -1): ViewRef { if (atIndex == -1) atIndex = this.length; - return this.viewManager.createViewInContainer(this.element, atIndex, protoViewRef, context, - bindings); + return this.viewManager.createEmbeddedViewInContainer(this.element, atIndex, templateRef); + } + + createHostView(protoViewRef: ProtoViewRef = null, atIndex: number = -1, + dynamicallyCreatedBindings: ResolvedBinding[] = null): ViewRef { + if (atIndex == -1) atIndex = this.length; + return this.viewManager.createHostViewInContainer(this.element, atIndex, protoViewRef, + dynamicallyCreatedBindings); } insert(viewRef: ViewRef, atIndex: number = -1): ViewRef { diff --git a/modules/angular2/src/core/compiler/view_manager.ts b/modules/angular2/src/core/compiler/view_manager.ts index 4064088feb..82d908f124 100644 --- a/modules/angular2/src/core/compiler/view_manager.ts +++ b/modules/angular2/src/core/compiler/view_manager.ts @@ -4,6 +4,7 @@ import * as viewModule from './view'; import {ElementRef} from './element_ref'; import {ProtoViewRef, ViewRef, internalView, internalProtoView} from './view_ref'; import {ViewContainerRef} from './view_container_ref'; +import {TemplateRef} from './template_ref'; import { Renderer, RenderViewRef, @@ -39,9 +40,11 @@ export class AppViewManager { /** * Return the first child element of the host element view. */ - // TODO(misko): remove https://github.com/angular/angular/issues/2891 getHostElement(hostViewRef: ViewRef): ElementRef { var hostView = internalView(hostViewRef); + if (hostView.proto.type !== ViewType.HOST) { + throw new BaseException('This operation is only allowed on host views'); + } return hostView.elementRefs[hostView.elementOffset]; } @@ -170,22 +173,42 @@ export class AppViewManager { * * See {@link AppViewManager#destroyViewInContainer}. */ - createViewInContainer(viewContainerLocation: ElementRef, atIndex: number, - protoViewRef: ProtoViewRef, context: ElementRef = null, - bindings: ResolvedBinding[] = null): ViewRef { + createEmbeddedViewInContainer(viewContainerLocation: ElementRef, atIndex: number, + templateRef: TemplateRef): ViewRef { + var protoView = internalProtoView(templateRef.protoViewRef); + if (protoView.type !== ViewType.EMBEDDED) { + throw new BaseException('This method can only be called with embedded ProtoViews!'); + } + return this._createViewInContainer(viewContainerLocation, atIndex, protoView, + templateRef.elementRef, null); + } + + /** + * + * See {@link AppViewManager#destroyViewInContainer}. + */ + createHostViewInContainer(viewContainerLocation: ElementRef, atIndex: number, + protoViewRef: ProtoViewRef, + imperativelyCreatedInjector: ResolvedBinding[]): ViewRef { var protoView = internalProtoView(protoViewRef); + if (protoView.type !== ViewType.HOST) { + throw new BaseException('This method can only be called with host ProtoViews!'); + } + return this._createViewInContainer(viewContainerLocation, atIndex, protoView, + viewContainerLocation, imperativelyCreatedInjector); + } + + /** + * + * See {@link AppViewManager#destroyViewInContainer}. + */ + _createViewInContainer(viewContainerLocation: ElementRef, atIndex: number, + protoView: viewModule.AppProtoView, context: ElementRef, + imperativelyCreatedInjector: ResolvedBinding[]): ViewRef { var parentView = internalView(viewContainerLocation.parentView); var boundElementIndex = viewContainerLocation.boundElementIndex; - var contextView = null; - var contextBoundElementIndex = null; - if (isPresent(context)) { - contextView = internalView(context.parentView); - contextBoundElementIndex = context.boundElementIndex; - } else { - contextView = parentView; - contextBoundElementIndex = boundElementIndex; - } - + var contextView = internalView(context.parentView); + var contextBoundElementIndex = context.boundElementIndex; var embeddedFragmentView = contextView.getNestedView(contextBoundElementIndex); var view; if (protoView.type === ViewType.EMBEDDED && isPresent(embeddedFragmentView) && @@ -194,7 +217,8 @@ export class AppViewManager { view = embeddedFragmentView; this._attachRenderView(parentView, boundElementIndex, atIndex, view); } else { - // Case 2: instantiate another copy of the template. This is a separate case + // Case 2: instantiate another copy of the template or a host ProtoView. + // This is a separate case // as we only inline one copy of the template into the parent view. view = this._createPooledView(protoView); this._attachRenderView(parentView, boundElementIndex, atIndex, view); @@ -203,7 +227,8 @@ export class AppViewManager { this._utils.attachViewInContainer(parentView, boundElementIndex, contextView, contextBoundElementIndex, atIndex, view); this._utils.hydrateViewInContainer(parentView, boundElementIndex, contextView, - contextBoundElementIndex, atIndex, bindings); + contextBoundElementIndex, atIndex, + imperativelyCreatedInjector); return view.ref; } diff --git a/modules/angular2/src/core/compiler/view_manager_utils.ts b/modules/angular2/src/core/compiler/view_manager_utils.ts index eb9e2c0877..6dce0f3f6b 100644 --- a/modules/angular2/src/core/compiler/view_manager_utils.ts +++ b/modules/angular2/src/core/compiler/view_manager_utils.ts @@ -6,6 +6,7 @@ import * as viewModule from './view'; import {internalView} from './view_ref'; import * as avmModule from './view_manager'; import {ElementRef} from './element_ref'; +import {TemplateRef} from './template_ref'; import {Renderer, RenderViewWithFragments} from 'angular2/src/render/api'; import {Locals} from 'angular2/change_detection'; import {RenderViewRef, RenderFragmentRef, ViewType} from 'angular2/src/render/api'; @@ -83,9 +84,9 @@ export class AppViewManagerUtils { // preBuiltObjects if (isPresent(elementInjector)) { - var embeddedProtoView = binder.hasEmbeddedProtoView() ? binder.nestedProtoView : null; + var templateRef = binder.hasEmbeddedProtoView() ? new TemplateRef(el) : null; preBuiltObjects[boundElementIndex] = - new eli.PreBuiltObjects(viewManager, currentView, el, embeddedProtoView); + new eli.PreBuiltObjects(viewManager, currentView, el, templateRef); } } currentView.init(protoView.protoChangeDetector.instantiate(currentView), elementInjectors, @@ -155,7 +156,7 @@ export class AppViewManagerUtils { hydrateViewInContainer(parentView: viewModule.AppView, boundElementIndex: number, contextView: viewModule.AppView, contextBoundElementIndex: number, - atIndex: number, bindings: ResolvedBinding[]) { + atIndex: number, imperativelyCreatedBindings: ResolvedBinding[]) { if (isBlank(contextView)) { contextView = parentView; contextBoundElementIndex = boundElementIndex; @@ -164,7 +165,9 @@ export class AppViewManagerUtils { var view = viewContainer.views[atIndex]; var elementInjector = contextView.elementInjectors[contextBoundElementIndex]; - var injector = isPresent(bindings) ? Injector.fromResolvedBindings(bindings) : null; + var injector = isPresent(imperativelyCreatedBindings) ? + Injector.fromResolvedBindings(imperativelyCreatedBindings) : + null; this._hydrateView(view, injector, elementInjector.getHost(), contextView.context, contextView.locals); } diff --git a/modules/angular2/src/directives/ng_for.ts b/modules/angular2/src/directives/ng_for.ts index c708fdc909..be0db5f41f 100644 --- a/modules/angular2/src/directives/ng_for.ts +++ b/modules/angular2/src/directives/ng_for.ts @@ -2,7 +2,7 @@ import {Directive} from 'angular2/annotations'; import { ViewContainerRef, ViewRef, - ProtoViewRef, + TemplateRef, Pipes, LifecycleEvent, Pipe, @@ -46,7 +46,7 @@ export class NgFor { _ngForOf: any; _pipe: Pipe; - constructor(private viewContainer: ViewContainerRef, private protoViewRef: ProtoViewRef, + constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef, private pipes: Pipes, private cdr: ChangeDetectorRef) {} set ngForOf(value: any) { @@ -79,7 +79,7 @@ export class NgFor { changes.forEachAddedItem((addedRecord) => insertTuples.push(new RecordViewTuple(addedRecord, null))); - NgFor.bulkInsert(insertTuples, this.viewContainer, this.protoViewRef); + NgFor.bulkInsert(insertTuples, this.viewContainer, this.templateRef); for (var i = 0; i < insertTuples.length; i++) { this._perViewChange(insertTuples[i].view, insertTuples[i].record); @@ -109,14 +109,14 @@ export class NgFor { } static bulkInsert(tuples: List, viewContainer: ViewContainerRef, - protoViewRef: ProtoViewRef): List { + templateRef: TemplateRef): List { tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex); for (var i = 0; i < tuples.length; i++) { var tuple = tuples[i]; if (isPresent(tuple.view)) { viewContainer.insert(tuple.view, tuple.record.currentIndex); } else { - tuple.view = viewContainer.create(protoViewRef, tuple.record.currentIndex); + tuple.view = viewContainer.createEmbeddedView(templateRef, tuple.record.currentIndex); } } return tuples; diff --git a/modules/angular2/src/directives/ng_if.ts b/modules/angular2/src/directives/ng_if.ts index 8c45871969..8d88e069a3 100644 --- a/modules/angular2/src/directives/ng_if.ts +++ b/modules/angular2/src/directives/ng_if.ts @@ -1,5 +1,5 @@ import {Directive} from 'angular2/annotations'; -import {ViewContainerRef, ProtoViewRef} from 'angular2/core'; +import {ViewContainerRef, TemplateRef} from 'angular2/core'; import {isBlank} from 'angular2/src/facade/lang'; /** @@ -27,19 +27,19 @@ import {isBlank} from 'angular2/src/facade/lang'; @Directive({selector: '[ng-if]', properties: ['ngIf']}) export class NgIf { viewContainer: ViewContainerRef; - protoViewRef: ProtoViewRef; + templateRef: TemplateRef; prevCondition: boolean; - constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) { + constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef) { this.viewContainer = viewContainer; this.prevCondition = null; - this.protoViewRef = protoViewRef; + this.templateRef = templateRef; } set ngIf(newCondition /* boolean */) { if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) { this.prevCondition = true; - this.viewContainer.create(this.protoViewRef); + this.viewContainer.createEmbeddedView(this.templateRef); } else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) { this.prevCondition = false; this.viewContainer.clear(); diff --git a/modules/angular2/src/directives/ng_switch.ts b/modules/angular2/src/directives/ng_switch.ts index 45f74aac83..556069801d 100644 --- a/modules/angular2/src/directives/ng_switch.ts +++ b/modules/angular2/src/directives/ng_switch.ts @@ -1,19 +1,19 @@ import {Directive} from 'angular2/annotations'; import {Parent} from 'angular2/di'; -import {ViewContainerRef, ProtoViewRef} from 'angular2/core'; +import {ViewContainerRef, TemplateRef} from 'angular2/core'; import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang'; import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection'; export class SwitchView { _viewContainerRef: ViewContainerRef; - _protoViewRef: ProtoViewRef; + _templateRef: TemplateRef; - constructor(viewContainerRef: ViewContainerRef, protoViewRef: ProtoViewRef) { - this._protoViewRef = protoViewRef; + constructor(viewContainerRef: ViewContainerRef, templateRef: TemplateRef) { + this._templateRef = templateRef; this._viewContainerRef = viewContainerRef; } - create() { this._viewContainerRef.create(this._protoViewRef); } + create() { this._viewContainerRef.createEmbeddedView(this._templateRef); } destroy() { this._viewContainerRef.clear(); } } @@ -156,12 +156,12 @@ export class NgSwitchWhen { _switch: NgSwitch; _view: SwitchView; - constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef, + constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, @Parent() sswitch: NgSwitch) { // `_whenDefault` is used as a marker for a not yet initialized value this._value = _whenDefault; this._switch = sswitch; - this._view = new SwitchView(viewContainer, protoViewRef); + this._view = new SwitchView(viewContainer, templateRef); } onDestroy() { this._switch; } @@ -186,9 +186,9 @@ export class NgSwitchWhen { */ @Directive({selector: '[ng-switch-default]'}) export class NgSwitchDefault { - constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef, + constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, @Parent() sswitch: NgSwitch) { - sswitch._registerView(_whenDefault, new SwitchView(viewContainer, protoViewRef)); + sswitch._registerView(_whenDefault, new SwitchView(viewContainer, templateRef)); } } diff --git a/modules/angular2/test/core/compiler/element_injector_spec.ts b/modules/angular2/test/core/compiler/element_injector_spec.ts index bfb216b35f..fd5108b587 100644 --- a/modules/angular2/test/core/compiler/element_injector_spec.ts +++ b/modules/angular2/test/core/compiler/element_injector_spec.ts @@ -43,7 +43,7 @@ import { import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Parent, Ancestor, Unbounded, InjectMetadata, ParentMetadata} from 'angular2/di'; import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; -import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref'; +import {TemplateRef} from 'angular2/src/core/compiler/template_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {DynamicChangeDetector, ChangeDetectorRef, Parser, Lexer} from 'angular2/change_detection'; import {QueryList} from 'angular2/src/core/compiler/query_list'; @@ -191,15 +191,15 @@ class NeedsViewContainer { } @Injectable() -class NeedsProtoViewRef { - protoViewRef; - constructor(ref: ProtoViewRef) { this.protoViewRef = ref; } +class NeedsTemplateRef { + templateRef; + constructor(ref: TemplateRef) { this.templateRef = ref; } } @Injectable() -class OptionallyInjectsProtoViewRef { - protoViewRef; - constructor(@Optional() ref: ProtoViewRef) { this.protoViewRef = ref; } +class OptionallyInjectsTemplateRef { + templateRef; + constructor(@Optional() ref: TemplateRef) { this.templateRef = ref; } } @Injectable() @@ -748,11 +748,11 @@ export function main() { }); it("should instantiate directives that depend on pre built objects", () => { - var protoView = new AppProtoView(null, null, null, null, null); - var bindings = ListWrapper.concat([NeedsProtoViewRef], extraBindings); - var inj = injector(bindings, null, false, new PreBuiltObjects(null, null, null, protoView)); + var templateRef = new TemplateRef(new DummyElementRef()); + var bindings = ListWrapper.concat([NeedsTemplateRef], extraBindings); + var inj = injector(bindings, null, false, new PreBuiltObjects(null, null, null, templateRef)); - expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); + expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef); }); it("should get directives from parent", () => { @@ -973,24 +973,24 @@ export function main() { expect(inj.get(NeedsViewContainer).viewContainer).toBeAnInstanceOf(ViewContainerRef); }); - it("should inject ProtoViewRef", () => { - var protoView = new AppProtoView(null, null, null, null, null); - var inj = injector(ListWrapper.concat([NeedsProtoViewRef], extraBindings), null, false, - new PreBuiltObjects(null, null, null, protoView)); + it("should inject TemplateRef", () => { + var templateRef = new TemplateRef(new DummyElementRef()); + var inj = injector(ListWrapper.concat([NeedsTemplateRef], extraBindings), null, false, + new PreBuiltObjects(null, null, null, templateRef)); - expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView)); + expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef); }); - it("should throw if there is no ProtoViewRef", () => { - expect(() => injector(ListWrapper.concat([NeedsProtoViewRef], extraBindings))) + it("should throw if there is no TemplateRef", () => { + expect(() => injector(ListWrapper.concat([NeedsTemplateRef], extraBindings))) .toThrowError( - `No provider for ProtoViewRef! (${stringify(NeedsProtoViewRef) } -> ProtoViewRef)`); + `No provider for TemplateRef! (${stringify(NeedsTemplateRef) } -> TemplateRef)`); }); - it('should inject null if there is no ProtoViewRef when the dependency is optional', () => { - var inj = injector(ListWrapper.concat([OptionallyInjectsProtoViewRef], extraBindings)); - var instance = inj.get(OptionallyInjectsProtoViewRef); - expect(instance.protoViewRef).toBeNull(); + it('should inject null if there is no TemplateRef when the dependency is optional', () => { + var inj = injector(ListWrapper.concat([OptionallyInjectsTemplateRef], extraBindings)); + var instance = inj.get(OptionallyInjectsTemplateRef); + expect(instance.templateRef).toBeNull(); }); }); diff --git a/modules/angular2/test/core/compiler/integration_spec.ts b/modules/angular2/test/core/compiler/integration_spec.ts index 3177d558c8..5c413bae7c 100644 --- a/modules/angular2/test/core/compiler/integration_spec.ts +++ b/modules/angular2/test/core/compiler/integration_spec.ts @@ -67,9 +67,11 @@ import {NgIf} from 'angular2/src/directives/ng_if'; import {NgFor} from 'angular2/src/directives/ng_for'; import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; -import {ProtoViewRef, ViewRef} from 'angular2/src/core/compiler/view_ref'; +import {ViewRef} from 'angular2/src/core/compiler/view_ref'; + import {Compiler} from 'angular2/src/core/compiler/compiler'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; +import {TemplateRef} from 'angular2/src/core/compiler/template_ref'; import {DomRenderer} from 'angular2/src/render/dom/dom_renderer'; import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; @@ -1385,7 +1387,7 @@ class DynamicViewport { var bindings = Injector.resolve([bind(MyService).toValue(myService)]); this.done = compiler.compileInHost(ChildCompUsingService) - .then((hostPv) => {vc.create(hostPv, 0, null, bindings)}); + .then((hostPv) => {vc.createHostView(hostPv, 0, bindings)}); } } @@ -1525,9 +1527,9 @@ class ChildComp2 { @Directive({selector: '[some-viewport]'}) @Injectable() class SomeViewport { - constructor(container: ViewContainerRef, protoView: ProtoViewRef) { - container.create(protoView).setLocal('some-tmpl', 'hello'); - container.create(protoView).setLocal('some-tmpl', 'again'); + constructor(container: ViewContainerRef, templateRef: TemplateRef) { + container.createEmbeddedView(templateRef).setLocal('some-tmpl', 'hello'); + container.createEmbeddedView(templateRef).setLocal('some-tmpl', 'again'); } } @@ -1677,12 +1679,8 @@ class NeedsPublicApi { @Directive({selector: '[toolbarpart]'}) @Injectable() class ToolbarPart { - protoViewRef: ProtoViewRef; - elementRef: ElementRef; - constructor(protoViewRef: ProtoViewRef, elementRef: ElementRef) { - this.elementRef = elementRef; - this.protoViewRef = protoViewRef; - } + templateRef: TemplateRef; + constructor(templateRef: TemplateRef) { this.templateRef = templateRef; } } @Directive({selector: '[toolbar-vc]', properties: ['toolbarVc']}) @@ -1692,7 +1690,7 @@ class ToolbarViewContainer { constructor(vc: ViewContainerRef) { this.vc = vc; } set toolbarVc(part: ToolbarPart) { - var view = this.vc.create(part.protoViewRef, 0, part.elementRef); + var view = this.vc.createEmbeddedView(part.templateRef, 0); view.setLocal('toolbarProp', 'From toolbar'); } } @@ -1858,7 +1856,7 @@ class ChildConsumingEventBus { class SomeImperativeViewport { view: ViewRef; anchor; - constructor(public vc: ViewContainerRef, public protoView: ProtoViewRef, + constructor(public vc: ViewContainerRef, public templateRef: TemplateRef, public renderer: DomRenderer, @Inject(ANCHOR_ELEMENT) anchor) { this.view = null; this.anchor = anchor; @@ -1870,7 +1868,7 @@ class SomeImperativeViewport { this.view = null; } if (value) { - this.view = this.vc.create(this.protoView); + this.view = this.vc.createEmbeddedView(this.templateRef); var nodes = this.renderer.getRootNodes(this.view.renderFragment); for (var i = 0; i < nodes.length; i++) { DOM.appendChild(this.anchor, nodes[i]); diff --git a/modules/angular2/test/core/compiler/projection_integration_spec.ts b/modules/angular2/test/core/compiler/projection_integration_spec.ts index 74fa39e259..822fa1eb5b 100644 --- a/modules/angular2/test/core/compiler/projection_integration_spec.ts +++ b/modules/angular2/test/core/compiler/projection_integration_spec.ts @@ -32,8 +32,8 @@ import { View, forwardRef, ViewContainerRef, - ProtoViewRef, ElementRef, + TemplateRef, bind } from 'angular2/angular2'; import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/render'; @@ -275,7 +275,7 @@ export function main() { main.query(By.directive(ProjectDirective)).inject(ProjectDirective); expect(main.nativeElement).toHaveText('START()END'); - projectDirective.show(sourceDirective.protoViewRef, sourceDirective.elementRef); + projectDirective.show(sourceDirective.templateRef); expect(main.nativeElement).toHaveText('START(A)END'); async.done(); }); @@ -298,7 +298,7 @@ export function main() { main.query(By.directive(ProjectDirective)).inject(ProjectDirective); expect(main.nativeElement).toHaveText('SIMPLE()START()END'); - projectDirective.show(sourceDirective.protoViewRef, sourceDirective.elementRef); + projectDirective.show(sourceDirective.templateRef); expect(main.nativeElement).toHaveText('SIMPLE()START(A)END'); async.done(); }); @@ -325,12 +325,12 @@ export function main() { main.query(By.directive(ProjectDirective)).inject(ProjectDirective); expect(main.nativeElement).toHaveText('(, B)START()END'); - projectDirective.show(sourceDirective.protoViewRef, sourceDirective.elementRef); + projectDirective.show(sourceDirective.templateRef); expect(main.nativeElement).toHaveText('(, B)START(A)END'); // Stamping ng-content multiple times should not produce the content multiple // times... - projectDirective.show(sourceDirective.protoViewRef, sourceDirective.elementRef); + projectDirective.show(sourceDirective.templateRef); expect(main.nativeElement).toHaveText('(, B)START(A)END'); async.done(); }); @@ -418,18 +418,15 @@ class MultipleContentTagsComponent { @Directive({selector: '[manual]'}) class ManualViewportDirective { - constructor(public vc: ViewContainerRef, public protoViewRef: ProtoViewRef, - public elementRef: ElementRef) {} - show() { this.vc.create(this.protoViewRef, 0); } + constructor(public vc: ViewContainerRef, public templateRef: TemplateRef) {} + show() { this.vc.createEmbeddedView(this.templateRef, 0); } hide() { this.vc.clear(); } } @Directive({selector: '[project]'}) class ProjectDirective { constructor(public vc: ViewContainerRef) {} - show(protoViewRef: ProtoViewRef, context: ElementRef) { - this.vc.create(protoViewRef, 0, context); - } + show(templateRef: TemplateRef) { this.vc.createEmbeddedView(templateRef, 0); } hide() { this.vc.clear(); } } diff --git a/modules/angular2/test/core/compiler/view_manager_spec.ts b/modules/angular2/test/core/compiler/view_manager_spec.ts index cc3daf844d..a742831e06 100644 --- a/modules/angular2/test/core/compiler/view_manager_spec.ts +++ b/modules/angular2/test/core/compiler/view_manager_spec.ts @@ -26,6 +26,7 @@ import { } from 'angular2/src/core/compiler/view'; import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; +import {TemplateRef} from 'angular2/src/core/compiler/template_ref'; import { Renderer, RenderViewRef, @@ -187,25 +188,27 @@ export function main() { var hostView: AppView; var childProtoView: AppProtoView; var vcRef: ElementRef; + var templateRef: TemplateRef; beforeEach(() => { childProtoView = createEmbeddedPv(); var hostProtoView = createHostPv( [createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]); hostView = internalView(manager.createRootHostView(wrapPv(hostProtoView), null, null)); vcRef = hostView.elementRefs[1]; + templateRef = new TemplateRef(hostView.elementRefs[1]); resetSpies(); }); describe('create the first view', () => { it('should create an AppViewContainer if not yet existing', () => { - manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null); + manager.createEmbeddedViewInContainer(vcRef, 0, templateRef); expect(hostView.viewContainers[1]).toBeTruthy(); }); it('should use an existing nested view', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); expect(childView.proto).toBe(childProtoView); expect(childView).toBe(hostView.views[2]); expect(viewListener.spy('viewCreated')).not.toHaveBeenCalled(); @@ -214,7 +217,7 @@ export function main() { it('should attach the fragment', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); expect(childView.proto).toBe(childProtoView); expect(hostView.viewContainers[1].views.length).toBe(1); expect(hostView.viewContainers[1].views[0]).toBe(childView); @@ -224,13 +227,13 @@ export function main() { it('should hydrate the view but not the render view', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); expect(childView.hydrated()).toBe(true); expect(renderer.spy('hydrateView')).not.toHaveBeenCalled(); }); it('should not set the EventDispatcher', () => { - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); expect(renderer.spy('setEventDispatcher')).not.toHaveBeenCalled(); }); @@ -240,13 +243,13 @@ export function main() { var firstChildView; beforeEach(() => { firstChildView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); resetSpies(); }); it('should create a new view', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); expect(childView.proto).toBe(childProtoView); expect(childView).not.toBe(firstChildView); expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(childView); @@ -259,7 +262,7 @@ export function main() { it('should attach the fragment', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); expect(childView.proto).toBe(childProtoView); expect(hostView.viewContainers[1].views[1]).toBe(childView); expect(renderer.spy('attachFragmentAfterFragment')) @@ -268,14 +271,14 @@ export function main() { it('should hydrate the view', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); expect(childView.hydrated()).toBe(true); expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(childView.render); }); it('should set the EventDispatcher', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); expect(renderer.spy('setEventDispatcher')) .toHaveBeenCalledWith(childView.render, childView); }); @@ -284,14 +287,14 @@ export function main() { describe('create another view when the first view has been returned', () => { beforeEach(() => { - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); manager.destroyViewInContainer(vcRef, 0); resetSpies(); }); it('should use an existing nested view', () => { var childView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); expect(childView.proto).toBe(childProtoView); expect(childView).toBe(hostView.views[2]); expect(viewListener.spy('viewCreated')).not.toHaveBeenCalled(); @@ -305,7 +308,7 @@ export function main() { it('should always create a new view and not use the embedded view', () => { var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]); var newHostView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(newHostPv), null)); + internalView(manager.createHostViewInContainer(vcRef, 0, wrapPv(newHostPv), null)); expect(newHostView.proto).toBe(newHostPv); expect(newHostView).not.toBe(hostView.views[2]); expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(newHostView); @@ -325,6 +328,7 @@ export function main() { var hostView: AppView; var childProtoView: AppProtoView; var vcRef: ElementRef; + var templateRef: TemplateRef; var firstChildView: AppView; beforeEach(() => { childProtoView = createEmbeddedPv(); @@ -332,8 +336,9 @@ export function main() { [createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]); hostView = internalView(manager.createRootHostView(wrapPv(hostProtoView), null, null)); vcRef = hostView.elementRefs[1]; + templateRef = new TemplateRef(hostView.elementRefs[1]); firstChildView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); resetSpies(); }); @@ -362,7 +367,7 @@ export function main() { var secondChildView; beforeEach(() => { secondChildView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); resetSpies(); }); @@ -393,6 +398,7 @@ export function main() { var hostView: AppView; var childProtoView: AppProtoView; var vcRef: ElementRef; + var templateRef: TemplateRef; var firstChildView: AppView; var secondChildView: AppView; beforeEach(() => { @@ -401,10 +407,11 @@ export function main() { [createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]); hostView = internalView(manager.createRootHostView(wrapPv(hostProtoView), null, null)); vcRef = hostView.elementRefs[1]; + templateRef = new TemplateRef(hostView.elementRefs[1]); firstChildView = - internalView(manager.createViewInContainer(vcRef, 0, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 0, templateRef)); secondChildView = - internalView(manager.createViewInContainer(vcRef, 1, wrapPv(childProtoView), null)); + internalView(manager.createEmbeddedViewInContainer(vcRef, 1, templateRef)); resetSpies(); }); @@ -438,6 +445,7 @@ export function main() { var childProtoView: AppProtoView; var nestedChildProtoView: AppProtoView; var vcRef: ElementRef; + var templateRef: TemplateRef; var nestedVcRefs: ElementRef[]; var childViews: AppView[]; var nestedChildViews: AppView[]; @@ -451,18 +459,18 @@ export function main() { [createNestedElBinder(createComponentPv([createNestedElBinder(childProtoView)]))]); hostView = internalView(manager.createRootHostView(wrapPv(hostProtoView), null, null)); vcRef = hostView.elementRefs[1]; + templateRef = new TemplateRef(hostView.elementRefs[1]); nestedChildViews = []; childViews = []; nestedVcRefs = []; for (var i = 0; i < 2; i++) { - var view = internalView( - manager.createViewInContainer(vcRef, i, wrapPv(childProtoView), null)); + var view = internalView(manager.createEmbeddedViewInContainer(vcRef, i, templateRef)); childViews.push(view); var nestedVcRef = view.elementRefs[view.elementOffset]; nestedVcRefs.push(nestedVcRef); for (var j = 0; j < 2; j++) { var nestedView = internalView( - manager.createViewInContainer(nestedVcRef, j, wrapPv(childProtoView), null)); + manager.createEmbeddedViewInContainer(nestedVcRef, j, templateRef)); nestedChildViews.push(nestedView); } }