feat(view): implemented loading component next to existing location
This commit is contained in:
		
							parent
							
								
									77b31ab42f
								
							
						
					
					
						commit
						681d06386d
					
				
							
								
								
									
										2
									
								
								modules/angular2/src/core/application.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								modules/angular2/src/core/application.js
									
									
									
									
										vendored
									
									
								
							| @ -75,7 +75,7 @@ function _injectorBindings(appComponentType): List<Binding> { | ||||
|         // We need to do this here to ensure that we create Testability and
 | ||||
|         // it's ready on the window for users.
 | ||||
|         registry.registerApplication(appElement, testability); | ||||
|         return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, null, injector); | ||||
|         return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, injector); | ||||
|       }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, | ||||
|         Testability, TestabilityRegistry]), | ||||
| 
 | ||||
|  | ||||
| @ -16,11 +16,13 @@ export class ComponentRef { | ||||
|   location:ElementRef; | ||||
|   instance:any; | ||||
|   componentView:AppView; | ||||
|   _dispose:Function; | ||||
| 
 | ||||
|   constructor(location:ElementRef, instance:any, componentView:AppView){ | ||||
|   constructor(location:ElementRef, instance:any, componentView:AppView, dispose:Function){ | ||||
|     this.location = location; | ||||
|     this.instance = instance; | ||||
|     this.componentView = componentView; | ||||
|     this._dispose = dispose; | ||||
|   } | ||||
| 
 | ||||
|   get injector() { | ||||
| @ -30,6 +32,10 @@ export class ComponentRef { | ||||
|   get hostView() { | ||||
|     return this.location.hostView; | ||||
|   } | ||||
| 
 | ||||
|   dispose() { | ||||
|     this._dispose(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -72,16 +78,16 @@ export class DynamicComponentLoader { | ||||
|       // from the component child views
 | ||||
|       // See ViewFactory.returnView
 | ||||
|       // See AppViewHydrator.dehydrateDynamicComponentView
 | ||||
|       return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView); | ||||
|       var dispose = () => {throw "Not implemented";}; | ||||
|       return new ComponentRef(location, location.elementInjector.getDynamicallyLoadedComponent(), componentView, dispose); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Loads a component as a child of the View given by the provided ElementRef. The loaded | ||||
|    * component receives injection normally as a hosted view. | ||||
|    * Loads a component in the element specified by elementOrSelector. The loaded component receives | ||||
|    * injection normally as a hosted view. | ||||
|    */ | ||||
|   loadIntoNewLocation(elementOrSelector:any, type:Type, location:ElementRef, | ||||
|                       injector:Injector = null):Promise<ComponentRef> { | ||||
|   loadIntoNewLocation(elementOrSelector:any, type:Type, injector:Injector = null):Promise<ComponentRef> { | ||||
|     this._assertTypeIsComponent(type); | ||||
| 
 | ||||
|     return  this._compiler.compileInHost(type).then(hostProtoView => { | ||||
| @ -91,9 +97,30 @@ export class DynamicComponentLoader { | ||||
|       // TODO(vsavkin): return a component ref that dehydrates the host view
 | ||||
|       // See ViewFactory.returnView
 | ||||
|       // See AppViewHydrator.dehydrateInPlaceHostView
 | ||||
|       var newLocation = new ElementRef(hostView.elementInjectors[0]); | ||||
|       var newLocation = hostView.elementInjectors[0].getElementRef(); | ||||
|       var component = hostView.elementInjectors[0].getComponent(); | ||||
|       return new ComponentRef(newLocation, component, hostView.componentChildViews[0]); | ||||
|       var dispose = () => {throw "Not implemented";}; | ||||
|       return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Loads a component next to the provided ElementRef. The loaded component receives | ||||
|    * injection normally as a hosted view. | ||||
|    */ | ||||
|   loadNextToExistingLocation(type:Type, location:ElementRef, injector:Injector = null):Promise<ComponentRef> { | ||||
|     this._assertTypeIsComponent(type); | ||||
| 
 | ||||
|     return this._compiler.compileInHost(type).then(hostProtoView => { | ||||
|       var hostView = location.viewContainer.create(-1, hostProtoView, injector); | ||||
| 
 | ||||
|       var newLocation = hostView.elementInjectors[0].getElementRef(); | ||||
|       var component = hostView.elementInjectors[0].getComponent(); | ||||
|       var dispose = () => { | ||||
|         var index = location.viewContainer.indexOf(hostView); | ||||
|         location.viewContainer.remove(index); | ||||
|       }; | ||||
|       return new ComponentRef(newLocation, component, hostView.componentChildViews[0], dispose); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -672,6 +672,10 @@ export class ElementInjector extends TreeNode { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   getElementRef() { | ||||
|     return new ElementRef(this); | ||||
|   } | ||||
| 
 | ||||
|   getDynamicallyLoadedComponent() { | ||||
|     return this._dynamicallyCreatedComponent; | ||||
|   } | ||||
| @ -741,7 +745,7 @@ export class ElementInjector extends TreeNode { | ||||
|     if (isPresent(dep.attributeName)) return this._buildAttribute(dep); | ||||
|     if (isPresent(dep.queryDirective)) return this._findQuery(dep.queryDirective).list; | ||||
|     if (dep.key.id === StaticKeys.instance().elementRefId) { | ||||
|       return new ElementRef(this); | ||||
|       return this.getElementRef(); | ||||
|     } | ||||
|     return this._getByKey(dep.key, dep.depth, dep.optional, requestor); | ||||
|   } | ||||
|  | ||||
| @ -92,6 +92,10 @@ export class ViewContainer { | ||||
|     return view; | ||||
|   } | ||||
| 
 | ||||
|   indexOf(view:viewModule.AppView) { | ||||
|     return ListWrapper.indexOf(this._views, view); | ||||
|   } | ||||
| 
 | ||||
|   remove(atIndex=-1) { | ||||
|     if (atIndex == -1) atIndex = this._views.length - 1; | ||||
|     var view = this._views[atIndex]; | ||||
|  | ||||
| @ -129,6 +129,9 @@ export class ListWrapper { | ||||
|   static filter(array, pred:Function) { | ||||
|     return array.filter(pred); | ||||
|   } | ||||
|   static indexOf(array, value, startIndex = -1) { | ||||
|     return array.indexOf(value, startIndex); | ||||
|   } | ||||
|   static any(list:List, pred:Function) { | ||||
|     for (var i = 0 ; i < list.length; ++i) { | ||||
|       if (pred(list[i])) return true; | ||||
|  | ||||
| @ -114,6 +114,9 @@ export class ListWrapper { | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|   static indexOf(array: List<any>, value, startIndex = -1) { | ||||
|     return array.indexOf(value, startIndex); | ||||
|   } | ||||
|   static reduce<T>(list: List<T>, | ||||
|                    fn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, | ||||
|                    init: T) { | ||||
|  | ||||
| @ -11,118 +11,194 @@ import { | ||||
|   inject, | ||||
|   beforeEachBindings, | ||||
|   it, | ||||
|   xit, | ||||
|   SpyObject, proxy | ||||
| } from 'angular2/test_lib'; | ||||
| import {IMPLEMENTS} from 'angular2/src/facade/lang'; | ||||
| import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; | ||||
| import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; | ||||
| import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; | ||||
|   xit | ||||
|   } from 'angular2/test_lib'; | ||||
| 
 | ||||
| import {TestBed} from 'angular2/src/test_lib/test_bed'; | ||||
| 
 | ||||
| import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations/annotations'; | ||||
| import {View} from 'angular2/src/core/annotations/view'; | ||||
| import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||
| import {Decorator, Viewport, Component} from 'angular2/src/core/annotations/annotations'; | ||||
| import {ElementRef, ElementInjector, ProtoElementInjector, PreBuiltObjects} from 'angular2/src/core/compiler/element_injector'; | ||||
| import {Compiler} from 'angular2/src/core/compiler/compiler'; | ||||
| import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; | ||||
| import {ViewFactory} from 'angular2/src/core/compiler/view_factory' | ||||
| import {AppViewHydrator} from 'angular2/src/core/compiler/view_hydrator'; | ||||
| import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||
| import {If} from 'angular2/src/directives/if'; | ||||
| 
 | ||||
| export function main() { | ||||
|   describe("DynamicComponentLoader", () => { | ||||
|     var compiler; | ||||
|     var viewFactory; | ||||
|     var directiveMetadataReader; | ||||
|     var viewHydrator; | ||||
|     var loader; | ||||
|   describe('DynamicComponentLoader', function () { | ||||
|     describe("loading into existing location", () => { | ||||
|       it('should work', inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|         tb.overrideView(MyComp, new View({ | ||||
|           template: '<dynamic-comp #dynamic></dynamic-comp>', | ||||
|           directives: [DynamicComp] | ||||
|         })); | ||||
| 
 | ||||
|     beforeEach( () => { | ||||
|       compiler = new SpyCompiler(); | ||||
|       viewFactory = new SpyViewFactory(); | ||||
|       viewHydrator = new SpyAppViewHydrator(); | ||||
|       directiveMetadataReader = new DirectiveMetadataReader(); | ||||
|       loader = new DynamicComponentLoader(compiler, directiveMetadataReader, viewFactory, viewHydrator); | ||||
|     }); | ||||
|         tb.createView(MyComp).then((view) => { | ||||
|           var dynamicComponent = view.rawView.locals.get("dynamic"); | ||||
|           expect(dynamicComponent).toBeAnInstanceOf(DynamicComp); | ||||
| 
 | ||||
|     function createProtoView() { | ||||
|       return new AppProtoView(null, null); | ||||
|     } | ||||
| 
 | ||||
|     function createEmptyView() { | ||||
|       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); | ||||
|       eli.instantiateDirectives(null, null, null, preBuiltObjects); | ||||
|       return new ElementRef(eli); | ||||
|     } | ||||
| 
 | ||||
|     describe("loadIntoExistingLocation", () => { | ||||
|       describe('Load errors', () => { | ||||
|         it('should throw when trying to load a decorator', () => { | ||||
|           expect(() => loader.loadIntoExistingLocation(SomeDecorator, null)) | ||||
|             .toThrowError("Could not load 'SomeDecorator' because it is not a component."); | ||||
|         }); | ||||
| 
 | ||||
|         it('should throw when trying to load a viewport', () => { | ||||
|           expect(() => loader.loadIntoExistingLocation(SomeViewport, null)) | ||||
|             .toThrowError("Could not load 'SomeViewport' because it is not a component."); | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       it('should compile, create and hydrate the view', inject([AsyncTestCompleter], (async) => { | ||||
|         var log = []; | ||||
|         var protoView = createProtoView(); | ||||
|         var hostView = createEmptyView(); | ||||
|         var childView = createEmptyView(); | ||||
|         viewHydrator.spy('hydrateDynamicComponentView').andCallFake( (hostView, boundElementIndex, | ||||
|             componentView, componentDirective, injector) => { | ||||
|           ListWrapper.push(log, ['hydrateDynamicComponentView', hostView, boundElementIndex, componentView]); | ||||
|         }); | ||||
|         viewFactory.spy('getView').andCallFake( (protoView) => { | ||||
|           ListWrapper.push(log, ['getView', protoView]); | ||||
|           return childView; | ||||
|         }); | ||||
|         compiler.spy('compile').andCallFake( (_) => PromiseWrapper.resolve(protoView)); | ||||
| 
 | ||||
|         var elementRef = createElementRef(hostView, 23); | ||||
|         loader.loadIntoExistingLocation(SomeComponent, elementRef).then( (componentRef) => { | ||||
|           expect(log[0]).toEqual(['getView', protoView]); | ||||
|           expect(log[1]).toEqual(['hydrateDynamicComponentView', hostView, 23, childView]); | ||||
|           async.done(); | ||||
|           dynamicComponent.done.then((_) => { | ||||
|             view.detectChanges(); | ||||
|             expect(view.rootNodes).toHaveText('hello'); | ||||
|             async.done(); | ||||
|           }); | ||||
|         }); | ||||
|       })); | ||||
| 
 | ||||
|       it('should inject dependencies of the dynamically-loaded component', inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|         tb.overrideView(MyComp, new View({ | ||||
|           template: '<dynamic-comp #dynamic></dynamic-comp>', | ||||
|           directives: [DynamicComp] | ||||
|         })); | ||||
| 
 | ||||
|         tb.createView(MyComp).then((view) => { | ||||
|           var dynamicComponent = view.rawView.locals.get("dynamic"); | ||||
|           dynamicComponent.done.then((ref) => { | ||||
|             expect(ref.instance.dynamicallyCreatedComponentService).toBeAnInstanceOf(DynamicallyCreatedComponentService); | ||||
|             async.done(); | ||||
|           }); | ||||
|         }); | ||||
|       })); | ||||
| 
 | ||||
|       it('should allow to destroy and create them via viewport directives', | ||||
|         inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<div><dynamic-comp #dynamic template="if: ctxBoolProp"></dynamic-comp></div>', | ||||
|             directives: [DynamicComp, If] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             view.context.ctxBoolProp = true; | ||||
|             view.detectChanges(); | ||||
|             var dynamicComponent = view.rawView.viewContainers[0].get(0).locals.get("dynamic"); | ||||
|             dynamicComponent.done.then((_) => { | ||||
|               view.detectChanges(); | ||||
|               expect(view.rootNodes).toHaveText('hello'); | ||||
| 
 | ||||
|               view.context.ctxBoolProp = false; | ||||
|               view.detectChanges(); | ||||
| 
 | ||||
|               expect(view.rawView.viewContainers[0].length).toBe(0); | ||||
|               expect(view.rootNodes).toHaveText(''); | ||||
| 
 | ||||
|               view.context.ctxBoolProp = true; | ||||
|               view.detectChanges(); | ||||
| 
 | ||||
|               var dynamicComponent = view.rawView.viewContainers[0].get(0).locals.get("dynamic"); | ||||
|               return dynamicComponent.done; | ||||
|             }).then((_) => { | ||||
|               view.detectChanges(); | ||||
|               expect(view.rootNodes).toHaveText('hello'); | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
|     }); | ||||
| 
 | ||||
|     describe("loading next to an existing location", () => { | ||||
|       it('should work', inject([DynamicComponentLoader, TestBed, AsyncTestCompleter], | ||||
|         (loader, tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<div><location #loc></location></div>', | ||||
|             directives: [Location] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             var location = view.rawView.locals.get("loc"); | ||||
| 
 | ||||
|             loader.loadNextToExistingLocation(DynamicallyLoaded, location.elementRef).then(ref => { | ||||
|               expect(view.rootNodes).toHaveText("Location;DynamicallyLoaded;") | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
| 
 | ||||
|       it('should return a disposable component ref', inject([DynamicComponentLoader, TestBed, AsyncTestCompleter], | ||||
|         (loader, tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<div><location #loc></location></div>', | ||||
|             directives: [Location] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             var location = view.rawView.locals.get("loc"); | ||||
|             loader.loadNextToExistingLocation(DynamicallyLoaded, location.elementRef).then(ref => { | ||||
|               loader.loadNextToExistingLocation(DynamicallyLoaded2, location.elementRef).then(ref2 => { | ||||
|                 expect(view.rootNodes).toHaveText("Location;DynamicallyLoaded;DynamicallyLoaded2;") | ||||
| 
 | ||||
|                 ref2.dispose(); | ||||
| 
 | ||||
|                 expect(view.rootNodes).toHaveText("Location;DynamicallyLoaded;") | ||||
| 
 | ||||
|                 async.done(); | ||||
|               }); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| @Decorator({selector: 'someDecorator'}) | ||||
| class SomeDecorator {} | ||||
| 
 | ||||
| @Viewport({selector: 'someViewport'}) | ||||
| class SomeViewport {} | ||||
| class DynamicallyCreatedComponentService { | ||||
| } | ||||
| 
 | ||||
| @Component({selector: 'someComponent'}) | ||||
| class SomeComponent {} | ||||
| @DynamicComponent({ | ||||
|   selector: 'dynamic-comp' | ||||
| }) | ||||
| class DynamicComp { | ||||
|   done; | ||||
| 
 | ||||
|   constructor(loader:DynamicComponentLoader, location:ElementRef) { | ||||
|     this.done = loader.loadIntoExistingLocation(DynamicallyCreatedCmp, location); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @proxy | ||||
| @IMPLEMENTS(Compiler) | ||||
| class SpyCompiler extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | ||||
| @Component({ | ||||
|   selector: 'hello-cmp', | ||||
|   injectables: [DynamicallyCreatedComponentService] | ||||
| }) | ||||
| @View({ | ||||
|   template: "{{greeting}}" | ||||
| }) | ||||
| class DynamicallyCreatedCmp { | ||||
|   greeting:string; | ||||
|   dynamicallyCreatedComponentService:DynamicallyCreatedComponentService; | ||||
| 
 | ||||
| @proxy | ||||
| @IMPLEMENTS(ViewFactory) | ||||
| class SpyViewFactory extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | ||||
|   constructor(a:DynamicallyCreatedComponentService) { | ||||
|     this.greeting = "hello"; | ||||
|     this.dynamicallyCreatedComponentService = a; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @proxy | ||||
| @IMPLEMENTS(AppViewHydrator) | ||||
| class SpyAppViewHydrator extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | ||||
| @Component({selector: 'dummy'}) | ||||
| @View({template: "DynamicallyLoaded;"}) | ||||
| class DynamicallyLoaded { | ||||
| } | ||||
| 
 | ||||
| @proxy | ||||
| @IMPLEMENTS(AppView) | ||||
| class SpyAppView extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | ||||
| @Component({selector: 'dummy'}) | ||||
| @View({template: "DynamicallyLoaded2;"}) | ||||
| class DynamicallyLoaded2 { | ||||
| } | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'location' | ||||
| }) | ||||
| @View({template: "Location;"}) | ||||
| class Location { | ||||
|   elementRef:ElementRef; | ||||
| 
 | ||||
|   constructor(elementRef:ElementRef) { | ||||
|     this.elementRef = elementRef; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @Component() | ||||
| @View({ | ||||
|   directives: [] | ||||
| }) | ||||
| class MyComp { | ||||
|   ctxBoolProp:boolean; | ||||
| 
 | ||||
|   constructor() { | ||||
|     this.ctxBoolProp = false; | ||||
|   } | ||||
| } | ||||
| @ -28,8 +28,6 @@ import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/cor | ||||
| import {View} from 'angular2/src/core/annotations/view'; | ||||
| import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility'; | ||||
| import {Attribute} from 'angular2/src/core/annotations/di'; | ||||
| import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||
| import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||
| 
 | ||||
| import {If} from 'angular2/src/directives/if'; | ||||
| 
 | ||||
| @ -643,75 +641,6 @@ export function main() { | ||||
|         })); | ||||
|       } | ||||
| 
 | ||||
|       describe("dynamic components", () => { | ||||
|         it('should support loading components dynamically', inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<dynamic-comp #dynamic></dynamic-comp>', | ||||
|             directives: [DynamicComp] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             var dynamicComponent = view.rawView.locals.get("dynamic"); | ||||
|             expect(dynamicComponent).toBeAnInstanceOf(DynamicComp); | ||||
| 
 | ||||
|             dynamicComponent.done.then((_) => { | ||||
|               view.detectChanges(); | ||||
|               expect(view.rootNodes).toHaveText('hello'); | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
| 
 | ||||
|         it('should inject dependencies of the dynamically-loaded component', inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<dynamic-comp #dynamic></dynamic-comp>', | ||||
|             directives: [DynamicComp] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             var dynamicComponent = view.rawView.locals.get("dynamic"); | ||||
|             dynamicComponent.done.then((ref) => { | ||||
|               expect(ref.instance.dynamicallyCreatedComponentService).toBeAnInstanceOf(DynamicallyCreatedComponentService); | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
| 
 | ||||
|         it('should allow to destroy and create them via viewport directives', | ||||
|             inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||
|           tb.overrideView(MyComp, new View({ | ||||
|             template: '<div><dynamic-comp #dynamic template="if: ctxBoolProp"></dynamic-comp></div>', | ||||
|             directives: [DynamicComp, If] | ||||
|           })); | ||||
| 
 | ||||
|           tb.createView(MyComp).then((view) => { | ||||
|             view.context.ctxBoolProp = true; | ||||
|             view.detectChanges(); | ||||
|             var dynamicComponent = view.rawView.viewContainers[0].get(0).locals.get("dynamic"); | ||||
|             dynamicComponent.done.then((_) => { | ||||
|               view.detectChanges(); | ||||
|               expect(view.rootNodes).toHaveText('hello'); | ||||
| 
 | ||||
|               view.context.ctxBoolProp = false; | ||||
|               view.detectChanges(); | ||||
| 
 | ||||
|               expect(view.rawView.viewContainers[0].length).toBe(0); | ||||
|               expect(view.rootNodes).toHaveText(''); | ||||
| 
 | ||||
|               view.context.ctxBoolProp = true; | ||||
|               view.detectChanges(); | ||||
| 
 | ||||
|               var dynamicComponent = view.rawView.viewContainers[0].get(0).locals.get("dynamic"); | ||||
|               return dynamicComponent.done; | ||||
|             }).then((_) => { | ||||
|               view.detectChanges(); | ||||
|               expect(view.rootNodes).toHaveText('hello'); | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
|       }); | ||||
| 
 | ||||
|       describe('dynamic ViewContainers', () => { | ||||
| 
 | ||||
|         it('should allow to create a ViewContainer at any bound location', | ||||
| @ -868,34 +797,6 @@ class DynamicViewport { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DynamicallyCreatedComponentService {} | ||||
| 
 | ||||
| @DynamicComponent({ | ||||
|   selector: 'dynamic-comp' | ||||
| }) | ||||
| class DynamicComp { | ||||
|   done; | ||||
|   constructor(loader:DynamicComponentLoader, location:ElementRef) { | ||||
|     this.done = loader.loadIntoExistingLocation(DynamicallyCreatedCmp, location); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'hello-cmp', | ||||
|   injectables: [DynamicallyCreatedComponentService] | ||||
| }) | ||||
| @View({ | ||||
|   template: "{{greeting}}" | ||||
| }) | ||||
| class DynamicallyCreatedCmp { | ||||
|   greeting:string; | ||||
|   dynamicallyCreatedComponentService:DynamicallyCreatedComponentService; | ||||
|   constructor(a:DynamicallyCreatedComponentService) { | ||||
|     this.greeting = "hello"; | ||||
|     this.dynamicallyCreatedComponentService = a; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @Decorator({ | ||||
|   selector: '[my-dir]', | ||||
|   properties: {'dirProp':'elprop'} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user