refactor(view): provide ViewContainers dynamically on any element
This commit is contained in:
@ -47,15 +47,15 @@ export function main() {
|
||||
}
|
||||
|
||||
function createEmptyView() {
|
||||
var view = new AppView(null, createProtoView(), MapWrapper.create());
|
||||
view.init(null, [], [], [], [], []);
|
||||
var view = new AppView(null, null, null, createProtoView(), MapWrapper.create());
|
||||
view.init(null, [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
|
||||
function createElementRef(view, boundElementIndex) {
|
||||
var peli = new ProtoElementInjector(null, boundElementIndex, []);
|
||||
var eli = new ElementInjector(peli, null);
|
||||
var preBuiltObjects = new PreBuiltObjects(view, null, null, null);
|
||||
var preBuiltObjects = new PreBuiltObjects(view, null, null);
|
||||
eli.instantiateDirectives(null, null, null, preBuiltObjects);
|
||||
return new ElementRef(eli);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class DummyDirective extends Directive {
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(AppView)
|
||||
class DummyView extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||
class DummyView extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}}
|
||||
|
||||
|
||||
class SimpleDirective {
|
||||
@ -203,7 +203,7 @@ class TestNode extends TreeNode {
|
||||
}
|
||||
|
||||
export function main() {
|
||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null);
|
||||
var appInjector = Injector.resolveAndCreate([]);
|
||||
|
||||
function humanize(tree, names:List) {
|
||||
@ -476,7 +476,7 @@ export function main() {
|
||||
|
||||
it("should instantiate directives that depend on pre built objects", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null, null));
|
||||
var inj = injector([NeedsView], null, null, new PreBuiltObjects(view, null, null));
|
||||
|
||||
expect(inj.get(NeedsView).view).toBe(view);
|
||||
});
|
||||
@ -602,28 +602,32 @@ export function main() {
|
||||
describe("pre built objects", function () {
|
||||
it("should return view", function () {
|
||||
var view = new DummyView();
|
||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null, null));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null));
|
||||
|
||||
expect(inj.get(AppView)).toEqual(view);
|
||||
});
|
||||
|
||||
it("should return element", function () {
|
||||
var element = new NgElement(null, null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null, null));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, element, null));
|
||||
|
||||
expect(inj.get(NgElement)).toEqual(element);
|
||||
});
|
||||
|
||||
it('should return viewContainer', function () {
|
||||
var viewContainer = new ViewContainer(null, null, null, null, null);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, viewContainer, null));
|
||||
var viewContainer = new ViewContainer(null, null, null);
|
||||
var view = new DummyView();
|
||||
view.spy('getOrCreateViewContainer').andCallFake( (index) => {
|
||||
return viewContainer;
|
||||
});
|
||||
var inj = injector([], null, null, new PreBuiltObjects(view, null, null));
|
||||
|
||||
expect(inj.get(ViewContainer)).toEqual(viewContainer);
|
||||
});
|
||||
|
||||
it('should return changeDetectorRef', function () {
|
||||
var cd = new DynamicChangeDetector(null, null, null, [], []);
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, null, cd));
|
||||
var inj = injector([], null, null, new PreBuiltObjects(null, null, cd));
|
||||
|
||||
expect(inj.get(ChangeDetectorRef)).toBe(cd.ref);
|
||||
});
|
||||
@ -710,12 +714,12 @@ export function main() {
|
||||
beforeEach( () => {
|
||||
renderer = new FakeRenderer();
|
||||
var protoView = new AppProtoView(null, null);
|
||||
view = new AppView(renderer, protoView, MapWrapper.create());
|
||||
view = new AppView(renderer, null, null, protoView, MapWrapper.create());
|
||||
view.render = new ViewRef();
|
||||
});
|
||||
|
||||
it('should be injectable and callable', () => {
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetter);
|
||||
component.setProp('foobar');
|
||||
@ -734,7 +738,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should be injectable and callable without specifying param type annotation', () => {
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null, null);
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||
var inj = injector([NeedsPropertySetterNoType], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetterNoType);
|
||||
component.setProp('foobar');
|
||||
@ -773,6 +777,16 @@ export function main() {
|
||||
var inj = injector([NeedsElementRef]);
|
||||
expect(inj.get(NeedsElementRef).elementRef).toBeAnInstanceOf(ElementRef);
|
||||
});
|
||||
|
||||
it('should return the viewContainer from the view', () => {
|
||||
var viewContainer = new ViewContainer(null, null, null);
|
||||
var view = new DummyView();
|
||||
view.spy('getOrCreateViewContainer').andCallFake( (index) => {
|
||||
return viewContainer;
|
||||
});
|
||||
var inj = injector([NeedsElementRef], null, null, new PreBuiltObjects(view, null, null));
|
||||
expect(inj.get(NeedsElementRef).elementRef.viewContainer).toBe(viewContainer);
|
||||
});
|
||||
});
|
||||
|
||||
describe('directive queries', () => {
|
||||
|
@ -34,6 +34,7 @@ import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||
import {If} from 'angular2/src/directives/if';
|
||||
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||
|
||||
export function main() {
|
||||
describe('integration tests', function() {
|
||||
@ -694,6 +695,27 @@ export function main() {
|
||||
}));
|
||||
});
|
||||
|
||||
describe('dynamic ViewContainers', () => {
|
||||
|
||||
it('should allow to create a ViewContainer at any bound location',
|
||||
inject([TestBed, AsyncTestCompleter, Compiler], (tb, async, compiler) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<div><dynamic-vp #dynamic></dynamic-vp></div>',
|
||||
directives: [DynamicViewport]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp).then((view) => {
|
||||
var dynamicVp = view.rawView.elementInjectors[0].get(DynamicViewport);
|
||||
dynamicVp.done.then( (_) => {
|
||||
view.detectChanges();
|
||||
expect(view.rootNodes).toHaveText('dynamic greet');
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
it('should support static attributes', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<input static type="text" title>',
|
||||
@ -774,9 +796,22 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
class DynamicallyCreatedComponentService {
|
||||
@Decorator({
|
||||
selector: 'dynamic-vp'
|
||||
})
|
||||
class DynamicViewport {
|
||||
done;
|
||||
constructor(vc:ViewContainer, inj:Injector, compiler:Compiler) {
|
||||
var myService = new MyService();
|
||||
myService.greeting = 'dynamic greet';
|
||||
this.done = compiler.compileInHost(ChildCompUsingService).then( (hostPv) => {
|
||||
vc.create(0, hostPv, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicallyCreatedComponentService {}
|
||||
|
||||
@DynamicComponent({
|
||||
selector: 'dynamic-comp'
|
||||
})
|
||||
@ -909,6 +944,19 @@ class ChildComp {
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child-cmp-svc'
|
||||
})
|
||||
@View({
|
||||
template: '{{ctxProp}}'
|
||||
})
|
||||
class ChildCompUsingService {
|
||||
ctxProp:string;
|
||||
constructor(service: MyService) {
|
||||
this.ctxProp = service.greeting;
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: 'some-directive'
|
||||
})
|
||||
|
@ -35,7 +35,7 @@ export function main() {
|
||||
});
|
||||
|
||||
function createViewFactory({capacity}):ViewFactory {
|
||||
return new ViewFactory(capacity, renderer);
|
||||
return new ViewFactory(capacity, renderer, null);
|
||||
}
|
||||
|
||||
function createProtoChangeDetector() {
|
||||
|
@ -80,19 +80,19 @@ export function main() {
|
||||
}
|
||||
|
||||
function createEmptyView() {
|
||||
var view = new AppView(renderer, createProtoView(), MapWrapper.create());
|
||||
var view = new AppView(renderer, null, null, createProtoView(), MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
view.init(changeDetector, [], [], [], [], []);
|
||||
view.init(changeDetector, [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
|
||||
function createHostView(pv, shadowView, componentInstance) {
|
||||
var view = new AppView(renderer, pv, MapWrapper.create());
|
||||
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
var eij = createElementInjector();
|
||||
eij.spy('getComponent').andCallFake( () => componentInstance );
|
||||
view.init(changeDetector, [eij], [eij],
|
||||
[null], [null], [shadowView]);
|
||||
[null], [shadowView]);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
115
modules/angular2/test/core/compiler/view_spec.js
vendored
Normal file
115
modules/angular2/test/core/compiler/view_spec.js
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
xdescribe,
|
||||
describe,
|
||||
el,
|
||||
dispatchEvent,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
beforeEachBindings,
|
||||
it,
|
||||
xit,
|
||||
SpyObject, proxy
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
||||
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
import {ChangeDetector} from 'angular2/change_detection';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {ElementInjector} from 'angular2/src/core/compiler/element_injector';
|
||||
|
||||
export function main() {
|
||||
describe('AppView', () => {
|
||||
var renderer;
|
||||
|
||||
beforeEach( () => {
|
||||
renderer = new SpyRenderer();
|
||||
});
|
||||
|
||||
function createElementInjector() {
|
||||
return new SpyElementInjector();
|
||||
}
|
||||
|
||||
function createEmptyElBinder() {
|
||||
return new ElementBinder(0, null, 0, null, null, null);
|
||||
}
|
||||
|
||||
function createEmbeddedProtoViewElBinder(nestedProtoView) {
|
||||
var binder = new ElementBinder(0, null, 0, null, null, null);
|
||||
binder.nestedProtoView = nestedProtoView;
|
||||
return binder;
|
||||
}
|
||||
|
||||
function createProtoView(binders = null) {
|
||||
if (isBlank(binders)) {
|
||||
binders = [];
|
||||
}
|
||||
var res = new AppProtoView(null, null);
|
||||
res.elementBinders = binders;
|
||||
return res;
|
||||
}
|
||||
|
||||
function createViewWithOneBoundElement(pv) {
|
||||
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
var eij = createElementInjector();
|
||||
view.init(changeDetector, [eij], [eij],
|
||||
[null], [null]);
|
||||
return view;
|
||||
}
|
||||
|
||||
describe('getOrCreateViewContainer()', () => {
|
||||
|
||||
it('should create a new container', () => {
|
||||
var pv = createProtoView([createEmptyElBinder()]);
|
||||
var view = createViewWithOneBoundElement(pv);
|
||||
expect(view.getOrCreateViewContainer(0) instanceof ViewContainer).toBe(true);
|
||||
});
|
||||
|
||||
it('should return an existing container', () => {
|
||||
var pv = createProtoView([createEmptyElBinder()]);
|
||||
var view = createViewWithOneBoundElement(pv);
|
||||
var vc = view.getOrCreateViewContainer(0);
|
||||
expect(view.getOrCreateViewContainer(0)).toBe(vc);
|
||||
});
|
||||
|
||||
it('should store an existing nestedProtoView in the container', () => {
|
||||
var defaultProtoView = createProtoView();
|
||||
var pv = createProtoView([createEmbeddedProtoViewElBinder(defaultProtoView)]);
|
||||
var view = createViewWithOneBoundElement(pv);
|
||||
var vc = view.getOrCreateViewContainer(0);
|
||||
expect(vc.defaultProtoView).toBe(defaultProtoView);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(Renderer)
|
||||
class SpyRenderer extends SpyObject {
|
||||
constructor(){super(Renderer);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ChangeDetector)
|
||||
class SpyChangeDetector extends SpyObject {
|
||||
constructor(){super(ChangeDetector);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ElementInjector)
|
||||
class SpyElementInjector extends SpyObject {
|
||||
constructor(){super(ElementInjector);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
Reference in New Issue
Block a user