feat(view): introduce free embedded views
Free embedded views are view instances that are created logically in the same was as views of a ViewContainer, but their dom nodes are not attached. BREAKING CHANGE: - `Renderer.detachFreeHostView` was renamed to `Renderer.detachFreeView` - `DomRenderer.getHostElement()` was generalized into `DomRenderer.getRootNodes()`
This commit is contained in:
parent
9ce0870f6c
commit
5030ffb01c
@ -23,12 +23,9 @@ import * as renderApi from 'angular2/src/render/api';
|
|||||||
import {EventDispatcher} from 'angular2/src/render/api';
|
import {EventDispatcher} from 'angular2/src/render/api';
|
||||||
|
|
||||||
export class AppViewContainer {
|
export class AppViewContainer {
|
||||||
views: List<AppView>;
|
// The order in this list matches the DOM order.
|
||||||
|
views: List<AppView> = [];
|
||||||
constructor() {
|
freeViews: List<AppView> = [];
|
||||||
// The order in this list matches the DOM order.
|
|
||||||
this.views = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,6 +115,24 @@ export class AppViewManager {
|
|||||||
this._destroyFreeHostView(parentView, hostView);
|
this._destroyFreeHostView(parentView, hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createFreeEmbeddedView(location: ElementRef, protoViewRef: ProtoViewRef,
|
||||||
|
injector: Injector = null): ViewRef {
|
||||||
|
var protoView = internalProtoView(protoViewRef);
|
||||||
|
var parentView = internalView(location.parentView);
|
||||||
|
var boundElementIndex = location.boundElementIndex;
|
||||||
|
|
||||||
|
var view = this._createPooledView(protoView);
|
||||||
|
this._utils.attachAndHydrateFreeEmbeddedView(parentView, boundElementIndex, view, injector);
|
||||||
|
this._viewHydrateRecurse(view);
|
||||||
|
return new ViewRef(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyFreeEmbeddedView(location: ElementRef, viewRef: ViewRef) {
|
||||||
|
var parentView = internalView(location.parentView);
|
||||||
|
var boundElementIndex = location.boundElementIndex;
|
||||||
|
this._destroyFreeEmbeddedView(parentView, boundElementIndex, internalView(viewRef));
|
||||||
|
}
|
||||||
|
|
||||||
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
createViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
|
||||||
protoViewRef: ProtoViewRef, context: ElementRef = null,
|
protoViewRef: ProtoViewRef, context: ElementRef = null,
|
||||||
injector: Injector = null): ViewRef {
|
injector: Injector = null): ViewRef {
|
||||||
@ -225,11 +243,18 @@ export class AppViewManager {
|
|||||||
|
|
||||||
_destroyFreeHostView(parentView, hostView) {
|
_destroyFreeHostView(parentView, hostView) {
|
||||||
this._viewDehydrateRecurse(hostView, true);
|
this._viewDehydrateRecurse(hostView, true);
|
||||||
this._renderer.detachFreeHostView(parentView.render, hostView.render);
|
this._renderer.detachFreeView(hostView.render);
|
||||||
this._utils.detachFreeHostView(parentView, hostView);
|
this._utils.detachFreeHostView(parentView, hostView);
|
||||||
this._destroyPooledView(hostView);
|
this._destroyPooledView(hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_destroyFreeEmbeddedView(parentView, boundElementIndex, view) {
|
||||||
|
this._viewDehydrateRecurse(view, false);
|
||||||
|
this._renderer.detachFreeView(view.render);
|
||||||
|
this._utils.detachFreeEmbeddedView(parentView, boundElementIndex, view);
|
||||||
|
this._destroyPooledView(view);
|
||||||
|
}
|
||||||
|
|
||||||
_viewHydrateRecurse(view: viewModule.AppView) {
|
_viewHydrateRecurse(view: viewModule.AppView) {
|
||||||
this._renderer.hydrateView(view.render);
|
this._renderer.hydrateView(view.render);
|
||||||
|
|
||||||
@ -260,6 +285,9 @@ export class AppViewManager {
|
|||||||
for (var j = vc.views.length - 1; j >= 0; j--) {
|
for (var j = vc.views.length - 1; j >= 0; j--) {
|
||||||
this._destroyViewInContainer(view, i, j);
|
this._destroyViewInContainer(view, i, j);
|
||||||
}
|
}
|
||||||
|
for (var j = vc.freeViews.length - 1; j >= 0; j--) {
|
||||||
|
this._destroyFreeEmbeddedView(view, i, j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,28 @@ export class AppViewManagerUtils {
|
|||||||
ListWrapper.remove(parentView.freeHostViews, hostView);
|
ListWrapper.remove(parentView.freeHostViews, hostView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachAndHydrateFreeEmbeddedView(parentView: viewModule.AppView, boundElementIndex: number,
|
||||||
|
view: viewModule.AppView, injector: Injector = null) {
|
||||||
|
parentView.changeDetector.addChild(view.changeDetector);
|
||||||
|
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
|
||||||
|
ListWrapper.push(viewContainer.freeViews, view);
|
||||||
|
var elementInjector = parentView.elementInjectors[boundElementIndex];
|
||||||
|
for (var i = view.rootElementInjectors.length - 1; i >= 0; i--) {
|
||||||
|
view.rootElementInjectors[i].link(elementInjector);
|
||||||
|
}
|
||||||
|
this._hydrateView(view, injector, elementInjector, parentView.context, parentView.locals);
|
||||||
|
}
|
||||||
|
|
||||||
|
detachFreeEmbeddedView(parentView: viewModule.AppView, boundElementIndex: number,
|
||||||
|
view: viewModule.AppView) {
|
||||||
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
|
view.changeDetector.remove();
|
||||||
|
ListWrapper.remove(viewContainer.freeViews, view);
|
||||||
|
for (var i = 0; i < view.rootElementInjectors.length; ++i) {
|
||||||
|
view.rootElementInjectors[i].unlink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attachViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
attachViewInContainer(parentView: viewModule.AppView, boundElementIndex: number,
|
||||||
contextView: viewModule.AppView, contextBoundElementIndex: number,
|
contextView: viewModule.AppView, contextBoundElementIndex: number,
|
||||||
atIndex: number, view: viewModule.AppView) {
|
atIndex: number, view: viewModule.AppView) {
|
||||||
@ -118,11 +140,7 @@ export class AppViewManagerUtils {
|
|||||||
contextBoundElementIndex = boundElementIndex;
|
contextBoundElementIndex = boundElementIndex;
|
||||||
}
|
}
|
||||||
parentView.changeDetector.addChild(view.changeDetector);
|
parentView.changeDetector.addChild(view.changeDetector);
|
||||||
var viewContainer = parentView.viewContainers[boundElementIndex];
|
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
|
||||||
if (isBlank(viewContainer)) {
|
|
||||||
viewContainer = new viewModule.AppViewContainer();
|
|
||||||
parentView.viewContainers[boundElementIndex] = viewContainer;
|
|
||||||
}
|
|
||||||
ListWrapper.insert(viewContainer.views, atIndex, view);
|
ListWrapper.insert(viewContainer.views, atIndex, view);
|
||||||
var sibling;
|
var sibling;
|
||||||
if (atIndex == 0) {
|
if (atIndex == 0) {
|
||||||
@ -208,6 +226,15 @@ export class AppViewManagerUtils {
|
|||||||
view.changeDetector.hydrate(view.context, view.locals, view);
|
view.changeDetector.hydrate(view.context, view.locals, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getOrCreateViewContainer(parentView: viewModule.AppView, boundElementIndex: number) {
|
||||||
|
var viewContainer = parentView.viewContainers[boundElementIndex];
|
||||||
|
if (isBlank(viewContainer)) {
|
||||||
|
viewContainer = new viewModule.AppViewContainer();
|
||||||
|
parentView.viewContainers[boundElementIndex] = viewContainer;
|
||||||
|
}
|
||||||
|
return viewContainer;
|
||||||
|
}
|
||||||
|
|
||||||
_setUpEventEmitters(view: viewModule.AppView, elementInjector: eli.ElementInjector,
|
_setUpEventEmitters(view: viewModule.AppView, elementInjector: eli.ElementInjector,
|
||||||
boundElementIndex: number) {
|
boundElementIndex: number) {
|
||||||
var emitters = elementInjector.getEventEmitterAccessors();
|
var emitters = elementInjector.getEventEmitterAccessors();
|
||||||
|
@ -237,9 +237,9 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detaches a free host view's element from the DOM.
|
* Detaches a free view's element from the DOM.
|
||||||
*/
|
*/
|
||||||
detachFreeHostView(parentHostViewRef: RenderViewRef, hostViewRef: RenderViewRef) {}
|
detachFreeView(view: RenderViewRef) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a regular view out of the given ProtoView
|
* Creates a regular view out of the given ProtoView
|
||||||
|
@ -47,9 +47,9 @@ export class DomRenderer extends Renderer {
|
|||||||
return new DomViewRef(this._createView(hostProtoView, element));
|
return new DomViewRef(this._createView(hostProtoView, element));
|
||||||
}
|
}
|
||||||
|
|
||||||
detachFreeHostView(parentHostViewRef: RenderViewRef, hostViewRef: RenderViewRef) {
|
detachFreeView(viewRef: RenderViewRef) {
|
||||||
var hostView = resolveInternalDomView(hostViewRef);
|
var view = resolveInternalDomView(viewRef);
|
||||||
this._removeViewNodes(hostView);
|
this._removeViewNodes(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
createView(protoViewRef: RenderProtoViewRef): RenderViewRef {
|
createView(protoViewRef: RenderProtoViewRef): RenderViewRef {
|
||||||
@ -83,9 +83,8 @@ export class DomRenderer extends Renderer {
|
|||||||
this._moveViewNodesIntoParent(componentView.shadowRoot, componentView);
|
this._moveViewNodesIntoParent(componentView.shadowRoot, componentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
getHostElement(hostViewRef: RenderViewRef) {
|
getRootNodes(viewRef: RenderViewRef): List</*node*/ any> {
|
||||||
var hostView = resolveInternalDomView(hostViewRef);
|
return resolveInternalDomView(viewRef).rootNodes;
|
||||||
return hostView.boundElements[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detachComponentView(hostViewRef: RenderViewRef, boundElementIndex: number,
|
detachComponentView(hostViewRef: RenderViewRef, boundElementIndex: number,
|
||||||
|
@ -257,7 +257,7 @@ class ImperativeViewComponentUsingNgComponent {
|
|||||||
renderer.setComponentViewRootNodes(shadowViewRef.render, [div]);
|
renderer.setComponentViewRootNodes(shadowViewRef.render, [div]);
|
||||||
this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, null)
|
this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, null)
|
||||||
.then((componentRef) => {
|
.then((componentRef) => {
|
||||||
var element = renderer.getHostElement(componentRef.hostView.render);
|
var element = renderer.getRootNodes(componentRef.hostView.render)[0];
|
||||||
DOM.appendChild(div, element);
|
DOM.appendChild(div, element);
|
||||||
return componentRef;
|
return componentRef;
|
||||||
});
|
});
|
||||||
|
@ -29,11 +29,12 @@ import {
|
|||||||
isJsObject,
|
isJsObject,
|
||||||
global,
|
global,
|
||||||
stringify,
|
stringify,
|
||||||
CONST
|
CONST,
|
||||||
|
CONST_EXPR
|
||||||
} from 'angular2/src/facade/lang';
|
} from 'angular2/src/facade/lang';
|
||||||
import {PromiseWrapper, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
import {PromiseWrapper, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
import {Injector, bind, Injectable, Binding, FORWARD_REF} from 'angular2/di';
|
import {Injector, bind, Injectable, Binding, FORWARD_REF, OpaqueToken, Inject} from 'angular2/di';
|
||||||
import {
|
import {
|
||||||
PipeRegistry,
|
PipeRegistry,
|
||||||
defaultPipeRegistry,
|
defaultPipeRegistry,
|
||||||
@ -63,17 +64,21 @@ import {NgIf} from 'angular2/src/directives/ng_if';
|
|||||||
import {NgFor} from 'angular2/src/directives/ng_for';
|
import {NgFor} from 'angular2/src/directives/ng_for';
|
||||||
|
|
||||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||||
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
|
import {ProtoViewRef, ViewRef} from 'angular2/src/core/compiler/view_ref';
|
||||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||||
|
|
||||||
import {DomRenderer} from 'angular2/src/render/dom/dom_renderer';
|
import {DomRenderer} from 'angular2/src/render/dom/dom_renderer';
|
||||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||||
|
|
||||||
|
const ANCHOR_ELEMENT = CONST_EXPR(new OpaqueToken('AnchorElement'));
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('integration tests', function() {
|
describe('integration tests', function() {
|
||||||
var ctx;
|
var ctx;
|
||||||
|
|
||||||
|
beforeEachBindings(() => [bind(ANCHOR_ELEMENT).toValue(el('<div></div>'))]);
|
||||||
|
|
||||||
beforeEach(() => { ctx = new MyComp(); });
|
beforeEach(() => { ctx = new MyComp(); });
|
||||||
|
|
||||||
|
|
||||||
@ -1124,6 +1129,28 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should support free embedded views',
|
||||||
|
inject([TestBed, AsyncTestCompleter, ANCHOR_ELEMENT], (tb, async, anchorElement) => {
|
||||||
|
tb.overrideView(MyComp, new viewAnn.View({
|
||||||
|
template: '<div><div *some-impvp="ctxBoolProp">hello</div></div>',
|
||||||
|
directives: [SomeImperativeViewport]
|
||||||
|
}));
|
||||||
|
tb.createView(MyComp).then((view) => {
|
||||||
|
view.detectChanges();
|
||||||
|
expect(anchorElement).toHaveText('');
|
||||||
|
|
||||||
|
view.context.ctxBoolProp = true;
|
||||||
|
view.detectChanges();
|
||||||
|
expect(anchorElement).toHaveText('hello');
|
||||||
|
|
||||||
|
view.context.ctxBoolProp = false;
|
||||||
|
view.detectChanges();
|
||||||
|
expect(view.rootNodes).toHaveText('');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
// Disabled until a solution is found, refs:
|
// Disabled until a solution is found, refs:
|
||||||
// - https://github.com/angular/angular/issues/776
|
// - https://github.com/angular/angular/issues/776
|
||||||
// - https://github.com/angular/angular/commit/81f3f32
|
// - https://github.com/angular/angular/commit/81f3f32
|
||||||
@ -1640,3 +1667,30 @@ class ChildConsumingEventBus {
|
|||||||
|
|
||||||
constructor(@Unbounded() bus: EventBus) { this.bus = bus; }
|
constructor(@Unbounded() bus: EventBus) { this.bus = bus; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive({selector: '[some-impvp]', properties: ['someImpvp']})
|
||||||
|
@Injectable()
|
||||||
|
class SomeImperativeViewport {
|
||||||
|
view: ViewRef;
|
||||||
|
anchor;
|
||||||
|
constructor(public element: ElementRef, public protoView: ProtoViewRef,
|
||||||
|
public viewManager: AppViewManager, public renderer: DomRenderer,
|
||||||
|
@Inject(ANCHOR_ELEMENT) anchor) {
|
||||||
|
this.view = null;
|
||||||
|
this.anchor = anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
set someImpvp(value: boolean) {
|
||||||
|
if (isPresent(this.view)) {
|
||||||
|
this.viewManager.destroyFreeEmbeddedView(this.element, this.view);
|
||||||
|
this.view = null;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
this.view = this.viewManager.createFreeEmbeddedView(this.element, this.protoView);
|
||||||
|
var nodes = this.renderer.getRootNodes(this.view.render);
|
||||||
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
|
DOM.appendChild(this.anchor, nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -377,8 +377,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should detach the render view', () => {
|
it('should detach the render view', () => {
|
||||||
manager.destroyFreeHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
manager.destroyFreeHostView(elementRef(wrapView(parentHostView), 0), wrapView(hostView));
|
||||||
expect(renderer.spy('detachFreeHostView'))
|
expect(renderer.spy('detachFreeView')).toHaveBeenCalledWith(hostRenderViewRef);
|
||||||
.toHaveBeenCalledWith(parentView.render, hostRenderViewRef);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the view to the pool', () => {
|
it('should return the view to the pool', () => {
|
||||||
@ -402,6 +401,101 @@ export function main() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('createFreeEmbeddedView', () => {
|
||||||
|
|
||||||
|
// Note: We don't add tests for recursion or viewpool here as we assume that
|
||||||
|
// this is using the same mechanism as the other methods...
|
||||||
|
|
||||||
|
describe('basic functionality', () => {
|
||||||
|
var parentView, childProtoView;
|
||||||
|
beforeEach(() => {
|
||||||
|
parentView = createView(createProtoView([createEmptyElBinder()]));
|
||||||
|
childProtoView = createProtoView();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the view', () => {
|
||||||
|
expect(internalView(manager.createFreeEmbeddedView(elementRef(wrapView(parentView), 0),
|
||||||
|
wrapPv(childProtoView), null)))
|
||||||
|
.toBe(createdViews[0]);
|
||||||
|
expect(createdViews[0].proto).toBe(childProtoView);
|
||||||
|
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(createdViews[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should attachAndHydrate the view', () => {
|
||||||
|
var injector = new Injector([], null, false);
|
||||||
|
manager.createFreeEmbeddedView(elementRef(wrapView(parentView), 0),
|
||||||
|
wrapPv(childProtoView), injector);
|
||||||
|
expect(utils.spy('attachAndHydrateFreeEmbeddedView'))
|
||||||
|
.toHaveBeenCalledWith(parentView, 0, createdViews[0], injector);
|
||||||
|
expect(renderer.spy('hydrateView')).toHaveBeenCalledWith(createdViews[0].render);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create and set the render view', () => {
|
||||||
|
manager.createFreeEmbeddedView(elementRef(wrapView(parentView), 0),
|
||||||
|
wrapPv(childProtoView), null);
|
||||||
|
expect(renderer.spy('createView')).toHaveBeenCalledWith(childProtoView.render);
|
||||||
|
expect(createdViews[0].render).toBe(createdRenderViews[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the event dispatcher', () => {
|
||||||
|
manager.createFreeEmbeddedView(elementRef(wrapView(parentView), 0),
|
||||||
|
wrapPv(childProtoView), null);
|
||||||
|
var cmpView = createdViews[0];
|
||||||
|
expect(renderer.spy('setEventDispatcher')).toHaveBeenCalledWith(cmpView.render, cmpView);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('destroyFreeEmbeddedView', () => {
|
||||||
|
describe('basic functionality', () => {
|
||||||
|
var parentView, childProtoView, childView;
|
||||||
|
beforeEach(() => {
|
||||||
|
parentView = createView(createProtoView([createEmptyElBinder()]));
|
||||||
|
childProtoView = createProtoView();
|
||||||
|
childView = internalView(manager.createFreeEmbeddedView(
|
||||||
|
elementRef(wrapView(parentView), 0), wrapPv(childProtoView), null));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detach', () => {
|
||||||
|
manager.destroyFreeEmbeddedView(elementRef(wrapView(parentView), 0), wrapView(childView));
|
||||||
|
expect(utils.spy('detachFreeEmbeddedView'))
|
||||||
|
.toHaveBeenCalledWith(parentView, 0, childView);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dehydrate', () => {
|
||||||
|
manager.destroyFreeEmbeddedView(elementRef(wrapView(parentView), 0), wrapView(childView));
|
||||||
|
expect(utils.spy('dehydrateView')).toHaveBeenCalledWith(childView);
|
||||||
|
expect(renderer.spy('dehydrateView')).toHaveBeenCalledWith(childView.render);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detach the render view', () => {
|
||||||
|
manager.destroyFreeEmbeddedView(elementRef(wrapView(parentView), 0), wrapView(childView));
|
||||||
|
expect(renderer.spy('detachFreeView')).toHaveBeenCalledWith(childView.render);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the view to the pool', () => {
|
||||||
|
manager.destroyFreeEmbeddedView(elementRef(wrapView(parentView), 0), wrapView(childView));
|
||||||
|
expect(viewPool.spy('returnView')).toHaveBeenCalledWith(childView);
|
||||||
|
expect(renderer.spy('destroyView')).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy the view if the pool is full', () => {
|
||||||
|
viewPool.spy('returnView').andReturn(false);
|
||||||
|
manager.destroyFreeEmbeddedView(elementRef(wrapView(parentView), 0), wrapView(childView));
|
||||||
|
expect(renderer.spy('destroyView')).toHaveBeenCalledWith(childView.render);
|
||||||
|
expect(viewListener.spy('viewDestroyed')).toHaveBeenCalledWith(childView);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('recursively destroyFreeEmbeddedView', () => {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('createRootHostView', () => {
|
describe('createRootHostView', () => {
|
||||||
|
|
||||||
var hostProtoView;
|
var hostProtoView;
|
||||||
|
@ -40,17 +40,16 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create and destroy free host views',
|
it('should create and destroy free views',
|
||||||
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
|
||||||
tb.compiler.compileHost(someComponent)
|
tb.compiler.compileHost(someComponent)
|
||||||
.then((hostProtoViewDto) => {
|
.then((hostProtoViewDto) => {
|
||||||
var view = new TestView(tb.renderer.createView(hostProtoViewDto.render));
|
var view = new TestView(tb.renderer.createView(hostProtoViewDto.render));
|
||||||
var hostElement = tb.renderer.getHostElement(view.viewRef);
|
var hostElement = tb.renderer.getRootNodes(view.viewRef)[0];
|
||||||
DOM.appendChild(tb.rootEl, hostElement);
|
DOM.appendChild(tb.rootEl, hostElement);
|
||||||
|
|
||||||
tb.renderer.detachFreeHostView(null, view.viewRef);
|
tb.renderer.detachFreeView(view.viewRef);
|
||||||
expect(DOM.parentElement(hostElement)).toBeFalsy();
|
expect(DOM.parentElement(hostElement)).toBeFalsy();
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -66,7 +66,7 @@ export class MdDialog {
|
|||||||
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
||||||
// directly on the document body (also needed for web workers stuff).
|
// directly on the document body (also needed for web workers stuff).
|
||||||
// Create a DOM node to serve as a physical host element for the dialog.
|
// Create a DOM node to serve as a physical host element for the dialog.
|
||||||
var dialogElement = this.domRenderer.getHostElement(containerRef.hostView.render);
|
var dialogElement = this.domRenderer.getRootNodes(containerRef.hostView.render)[0];
|
||||||
DOM.appendChild(DOM.query('body'), dialogElement);
|
DOM.appendChild(DOM.query('body'), dialogElement);
|
||||||
|
|
||||||
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
||||||
@ -111,7 +111,7 @@ export class MdDialog {
|
|||||||
.then((componentRef) => {
|
.then((componentRef) => {
|
||||||
// TODO(tbosch): clean this up when we have custom renderers
|
// TODO(tbosch): clean this up when we have custom renderers
|
||||||
// (https://github.com/angular/angular/issues/1807)
|
// (https://github.com/angular/angular/issues/1807)
|
||||||
var backdropElement = this.domRenderer.getHostElement(componentRef.hostView.render);
|
var backdropElement = this.domRenderer.getRootNodes(componentRef.hostView.render)[0];
|
||||||
DOM.addClass(backdropElement, 'md-backdrop');
|
DOM.addClass(backdropElement, 'md-backdrop');
|
||||||
DOM.appendChild(DOM.query('body'), backdropElement);
|
DOM.appendChild(DOM.query('body'), backdropElement);
|
||||||
return componentRef;
|
return componentRef;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user