angular2
Version:
Angular 2 - a web framework for modern web apps
195 lines (164 loc) • 7.18 kB
text/typescript
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);
}
}
}