UNPKG

angular2

Version:

Angular 2 - a web framework for modern web apps

195 lines (164 loc) 7.18 kB
import {ListWrapper} from 'angular2/src/facade/collection'; import {unimplemented} from 'angular2/src/facade/exceptions'; import {Injector} from 'angular2/src/core/di/injector'; import {isPresent, isBlank} from 'angular2/src/facade/lang'; import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile'; import {AppElement} from './element'; import {ElementRef} from './element_ref'; import {TemplateRef, TemplateRef_} from './template_ref'; import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref'; import {ComponentFactory, ComponentRef} from './component_factory'; /** * Represents a container where one or more Views can be attached. * * The container can contain two kinds of Views. Host Views, created by instantiating a * {@link Component} via {@link #createComponent}, and Embedded Views, created by instantiating an * {@link TemplateRef Embedded Template} via {@link #createEmbeddedView}. * * The location of the View Container within the containing View is specified by the Anchor * `element`. Each View Container can have only one Anchor Element and each Anchor Element can only * have a single View Container. * * Root elements of Views attached to this container become siblings of the Anchor Element in * the Rendered View. * * To access a `ViewContainerRef` of an Element, you can either place a {@link Directive} injected * with `ViewContainerRef` on the Element, or you obtain it via a {@link ViewChild} query. */ export abstract class ViewContainerRef { /** * Anchor element that specifies the location of this container in the containing View. * <!-- TODO: rename to anchorElement --> */ get element(): ElementRef { return <ElementRef>unimplemented(); } get injector(): Injector { return <Injector>unimplemented(); } get parentInjector(): Injector { return <Injector>unimplemented(); } /** * Destroys all Views in this container. */ abstract clear(): void; /** * Returns the {@link ViewRef} for the View located in this container at the specified index. */ abstract get(index: number): ViewRef; /** * Returns the number of Views currently attached to this container. */ get length(): number { return <number>unimplemented(); }; /** * Instantiates an Embedded View based on the {@link TemplateRef `templateRef`} and inserts it * into this container at the specified `index`. * * If `index` is not specified, the new View will be inserted as the last View in the container. * * Returns the {@link ViewRef} for the newly created View. */ abstract createEmbeddedView(templateRef: TemplateRef, index?: number): EmbeddedViewRef; /** * Instantiates a single {@link Component} and inserts its Host View into this container at the * specified `index`. * * The component is instantiated using its {@link ComponentFactory} which can be * obtained via {@link ComponentResolver#resolveComponent}. * * If `index` is not specified, the new View will be inserted as the last View in the container. * * You can optionally specify the {@link Injector} that will be used as parent for the Component. * * Returns the {@link ComponentRef} of the Host View created for the newly instantiated Component. */ abstract createComponent(componentFactory: ComponentFactory, index?: number, injector?: Injector, projectableNodes?: any[][]): ComponentRef; /** * Inserts a View identified by a {@link ViewRef} into the container at the specified `index`. * * If `index` is not specified, the new View will be inserted as the last View in the container. * * Returns the inserted {@link ViewRef}. */ abstract insert(viewRef: ViewRef, index?: number): ViewRef; /** * Returns the index of the View, specified via {@link ViewRef}, within the current container or * `-1` if this container doesn't contain the View. */ abstract indexOf(viewRef: ViewRef): number; /** * Destroys a View attached to this container at the specified `index`. * * If `index` is not specified, the last View in the container will be removed. */ abstract remove(index?: number): void; /** * Use along with {@link #insert} to move a View within the current container. * * If the `index` param is omitted, the last {@link ViewRef} is detached. */ abstract detach(index?: number): ViewRef; } export class ViewContainerRef_ implements ViewContainerRef { constructor(private _element: AppElement) {} get(index: number): EmbeddedViewRef { return this._element.nestedViews[index].ref; } get length(): number { var views = this._element.nestedViews; return isPresent(views) ? views.length : 0; } get element(): ElementRef { return this._element.elementRef; } get injector(): Injector { return this._element.injector; } get parentInjector(): Injector { return this._element.parentInjector; } // TODO(rado): profile and decide whether bounds checks should be added // to the methods below. createEmbeddedView(templateRef: TemplateRef, index: number = -1): EmbeddedViewRef { var viewRef: EmbeddedViewRef = templateRef.createEmbeddedView(); this.insert(viewRef, index); return viewRef; } /** @internal */ _createComponentInContainerScope: WtfScopeFn = wtfCreateScope('ViewContainerRef#createComponent()'); createComponent(componentFactory: ComponentFactory, index: number = -1, injector: Injector = null, projectableNodes: any[][] = null): ComponentRef { var s = this._createComponentInContainerScope(); var contextInjector = isPresent(injector) ? injector : this._element.parentInjector; var componentRef = componentFactory.create(contextInjector, projectableNodes); this.insert(componentRef.hostView, index); return wtfLeave(s, componentRef); } /** @internal */ _insertScope = wtfCreateScope('ViewContainerRef#insert()'); // TODO(i): refactor insert+remove into move insert(viewRef: ViewRef, index: number = -1): ViewRef { var s = this._insertScope(); if (index == -1) index = this.length; var viewRef_ = <ViewRef_>viewRef; this._element.attachView(viewRef_.internalView, index); return wtfLeave(s, viewRef_); } indexOf(viewRef: ViewRef): number { return ListWrapper.indexOf(this._element.nestedViews, (<ViewRef_>viewRef).internalView); } /** @internal */ _removeScope = wtfCreateScope('ViewContainerRef#remove()'); // TODO(i): rename to destroy remove(index: number = -1): void { var s = this._removeScope(); if (index == -1) index = this.length - 1; var view = this._element.detachView(index); view.destroy(); // view is intentionally not returned to the client. wtfLeave(s); } /** @internal */ _detachScope = wtfCreateScope('ViewContainerRef#detach()'); // TODO(i): refactor insert+remove into move detach(index: number = -1): ViewRef { var s = this._detachScope(); if (index == -1) index = this.length - 1; var view = this._element.detachView(index); return wtfLeave(s, view.ref); } clear() { for (var i = this.length - 1; i >= 0; i--) { this.remove(i); } } }