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
 |         // We need to do this here to ensure that we create Testability and
 | ||||||
|         // it's ready on the window for users.
 |         // it's ready on the window for users.
 | ||||||
|         registry.registerApplication(appElement, testability); |         registry.registerApplication(appElement, testability); | ||||||
|         return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, null, injector); |         return dynamicComponentLoader.loadIntoNewLocation(appElement, appComponentAnnotatedType.type, injector); | ||||||
|       }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, |       }, [DynamicComponentLoader, Injector, appElementToken, appComponentAnnotatedTypeToken, | ||||||
|         Testability, TestabilityRegistry]), |         Testability, TestabilityRegistry]), | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,11 +16,13 @@ export class ComponentRef { | |||||||
|   location:ElementRef; |   location:ElementRef; | ||||||
|   instance:any; |   instance:any; | ||||||
|   componentView:AppView; |   componentView:AppView; | ||||||
|  |   _dispose:Function; | ||||||
| 
 | 
 | ||||||
|   constructor(location:ElementRef, instance:any, componentView:AppView){ |   constructor(location:ElementRef, instance:any, componentView:AppView, dispose:Function){ | ||||||
|     this.location = location; |     this.location = location; | ||||||
|     this.instance = instance; |     this.instance = instance; | ||||||
|     this.componentView = componentView; |     this.componentView = componentView; | ||||||
|  |     this._dispose = dispose; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   get injector() { |   get injector() { | ||||||
| @ -30,6 +32,10 @@ export class ComponentRef { | |||||||
|   get hostView() { |   get hostView() { | ||||||
|     return this.location.hostView; |     return this.location.hostView; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   dispose() { | ||||||
|  |     this._dispose(); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -72,16 +78,16 @@ export class DynamicComponentLoader { | |||||||
|       // from the component child views
 |       // from the component child views
 | ||||||
|       // See ViewFactory.returnView
 |       // See ViewFactory.returnView
 | ||||||
|       // See AppViewHydrator.dehydrateDynamicComponentView
 |       // 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 |    * Loads a component in the element specified by elementOrSelector. The loaded component receives | ||||||
|    * component receives injection normally as a hosted view. |    * injection normally as a hosted view. | ||||||
|    */ |    */ | ||||||
|   loadIntoNewLocation(elementOrSelector:any, type:Type, location:ElementRef, |   loadIntoNewLocation(elementOrSelector:any, type:Type, injector:Injector = null):Promise<ComponentRef> { | ||||||
|                       injector:Injector = null):Promise<ComponentRef> { |  | ||||||
|     this._assertTypeIsComponent(type); |     this._assertTypeIsComponent(type); | ||||||
| 
 | 
 | ||||||
|     return  this._compiler.compileInHost(type).then(hostProtoView => { |     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
 |       // TODO(vsavkin): return a component ref that dehydrates the host view
 | ||||||
|       // See ViewFactory.returnView
 |       // See ViewFactory.returnView
 | ||||||
|       // See AppViewHydrator.dehydrateInPlaceHostView
 |       // See AppViewHydrator.dehydrateInPlaceHostView
 | ||||||
|       var newLocation = new ElementRef(hostView.elementInjectors[0]); |       var newLocation = hostView.elementInjectors[0].getElementRef(); | ||||||
|       var component = hostView.elementInjectors[0].getComponent(); |       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() { |   getDynamicallyLoadedComponent() { | ||||||
|     return this._dynamicallyCreatedComponent; |     return this._dynamicallyCreatedComponent; | ||||||
|   } |   } | ||||||
| @ -741,7 +745,7 @@ export class ElementInjector extends TreeNode { | |||||||
|     if (isPresent(dep.attributeName)) return this._buildAttribute(dep); |     if (isPresent(dep.attributeName)) return this._buildAttribute(dep); | ||||||
|     if (isPresent(dep.queryDirective)) return this._findQuery(dep.queryDirective).list; |     if (isPresent(dep.queryDirective)) return this._findQuery(dep.queryDirective).list; | ||||||
|     if (dep.key.id === StaticKeys.instance().elementRefId) { |     if (dep.key.id === StaticKeys.instance().elementRefId) { | ||||||
|       return new ElementRef(this); |       return this.getElementRef(); | ||||||
|     } |     } | ||||||
|     return this._getByKey(dep.key, dep.depth, dep.optional, requestor); |     return this._getByKey(dep.key, dep.depth, dep.optional, requestor); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -92,6 +92,10 @@ export class ViewContainer { | |||||||
|     return view; |     return view; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   indexOf(view:viewModule.AppView) { | ||||||
|  |     return ListWrapper.indexOf(this._views, view); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   remove(atIndex=-1) { |   remove(atIndex=-1) { | ||||||
|     if (atIndex == -1) atIndex = this._views.length - 1; |     if (atIndex == -1) atIndex = this._views.length - 1; | ||||||
|     var view = this._views[atIndex]; |     var view = this._views[atIndex]; | ||||||
|  | |||||||
| @ -129,6 +129,9 @@ export class ListWrapper { | |||||||
|   static filter(array, pred:Function) { |   static filter(array, pred:Function) { | ||||||
|     return array.filter(pred); |     return array.filter(pred); | ||||||
|   } |   } | ||||||
|  |   static indexOf(array, value, startIndex = -1) { | ||||||
|  |     return array.indexOf(value, startIndex); | ||||||
|  |   } | ||||||
|   static any(list:List, pred:Function) { |   static any(list:List, pred:Function) { | ||||||
|     for (var i = 0 ; i < list.length; ++i) { |     for (var i = 0 ; i < list.length; ++i) { | ||||||
|       if (pred(list[i])) return true; |       if (pred(list[i])) return true; | ||||||
|  | |||||||
| @ -114,6 +114,9 @@ export class ListWrapper { | |||||||
|     } |     } | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
|  |   static indexOf(array: List<any>, value, startIndex = -1) { | ||||||
|  |     return array.indexOf(value, startIndex); | ||||||
|  |   } | ||||||
|   static reduce<T>(list: List<T>, |   static reduce<T>(list: List<T>, | ||||||
|                    fn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, |                    fn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, | ||||||
|                    init: T) { |                    init: T) { | ||||||
|  | |||||||
| @ -11,118 +11,194 @@ import { | |||||||
|   inject, |   inject, | ||||||
|   beforeEachBindings, |   beforeEachBindings, | ||||||
|   it, |   it, | ||||||
|   xit, |   xit | ||||||
|   SpyObject, proxy |   } from 'angular2/test_lib'; | ||||||
| } from 'angular2/test_lib'; | 
 | ||||||
| import {IMPLEMENTS} from 'angular2/src/facade/lang'; | import {TestBed} from 'angular2/src/test_lib/test_bed'; | ||||||
| import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; | 
 | ||||||
| import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; | import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations/annotations'; | ||||||
| import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; | import {View} from 'angular2/src/core/annotations/view'; | ||||||
| import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||||
| import {Decorator, Viewport, Component} from 'angular2/src/core/annotations/annotations'; | import {ElementRef} from 'angular2/src/core/compiler/element_injector'; | ||||||
| import {ElementRef, ElementInjector, ProtoElementInjector, PreBuiltObjects} from 'angular2/src/core/compiler/element_injector'; | import {If} from 'angular2/src/directives/if'; | ||||||
| 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'; |  | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe("DynamicComponentLoader", () => { |   describe('DynamicComponentLoader', function () { | ||||||
|     var compiler; |     describe("loading into existing location", () => { | ||||||
|     var viewFactory; |       it('should work', inject([TestBed, AsyncTestCompleter], (tb, async) => { | ||||||
|     var directiveMetadataReader; |         tb.overrideView(MyComp, new View({ | ||||||
|     var viewHydrator; |           template: '<dynamic-comp #dynamic></dynamic-comp>', | ||||||
|     var loader; |           directives: [DynamicComp] | ||||||
|  |         })); | ||||||
| 
 | 
 | ||||||
|     beforeEach( () => { |         tb.createView(MyComp).then((view) => { | ||||||
|       compiler = new SpyCompiler(); |           var dynamicComponent = view.rawView.locals.get("dynamic"); | ||||||
|       viewFactory = new SpyViewFactory(); |           expect(dynamicComponent).toBeAnInstanceOf(DynamicComp); | ||||||
|       viewHydrator = new SpyAppViewHydrator(); |  | ||||||
|       directiveMetadataReader = new DirectiveMetadataReader(); |  | ||||||
|       loader = new DynamicComponentLoader(compiler, directiveMetadataReader, viewFactory, viewHydrator); |  | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     function createProtoView() { |           dynamicComponent.done.then((_) => { | ||||||
|       return new AppProtoView(null, null); |             view.detectChanges(); | ||||||
|     } |             expect(view.rootNodes).toHaveText('hello'); | ||||||
| 
 |             async.done(); | ||||||
|     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(); |  | ||||||
|         }); |         }); | ||||||
|       })); |       })); | ||||||
| 
 | 
 | ||||||
|  |       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 DynamicallyCreatedComponentService { | ||||||
| class SomeViewport {} | } | ||||||
| 
 | 
 | ||||||
| @Component({selector: 'someComponent'}) | @DynamicComponent({ | ||||||
| class SomeComponent {} |   selector: 'dynamic-comp' | ||||||
|  | }) | ||||||
|  | class DynamicComp { | ||||||
|  |   done; | ||||||
| 
 | 
 | ||||||
|  |   constructor(loader:DynamicComponentLoader, location:ElementRef) { | ||||||
|  |     this.done = loader.loadIntoExistingLocation(DynamicallyCreatedCmp, location); | ||||||
|  |   } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @proxy | @Component({ | ||||||
| @IMPLEMENTS(Compiler) |   selector: 'hello-cmp', | ||||||
| class SpyCompiler extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} |   injectables: [DynamicallyCreatedComponentService] | ||||||
|  | }) | ||||||
|  | @View({ | ||||||
|  |   template: "{{greeting}}" | ||||||
|  | }) | ||||||
|  | class DynamicallyCreatedCmp { | ||||||
|  |   greeting:string; | ||||||
|  |   dynamicallyCreatedComponentService:DynamicallyCreatedComponentService; | ||||||
| 
 | 
 | ||||||
| @proxy |   constructor(a:DynamicallyCreatedComponentService) { | ||||||
| @IMPLEMENTS(ViewFactory) |     this.greeting = "hello"; | ||||||
| class SpyViewFactory extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} |     this.dynamicallyCreatedComponentService = a; | ||||||
|  |   } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @proxy | @Component({selector: 'dummy'}) | ||||||
| @IMPLEMENTS(AppViewHydrator) | @View({template: "DynamicallyLoaded;"}) | ||||||
| class SpyAppViewHydrator extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | class DynamicallyLoaded { | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @proxy | @Component({selector: 'dummy'}) | ||||||
| @IMPLEMENTS(AppView) | @View({template: "DynamicallyLoaded2;"}) | ||||||
| class SpyAppView extends SpyObject {noSuchMethod(m){return super.noSuchMethod(m)}} | 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 {View} from 'angular2/src/core/annotations/view'; | ||||||
| import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility'; | import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility'; | ||||||
| import {Attribute} from 'angular2/src/core/annotations/di'; | 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'; | 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', () => { |       describe('dynamic ViewContainers', () => { | ||||||
| 
 | 
 | ||||||
|         it('should allow to create a ViewContainer at any bound location', |         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({ | @Decorator({ | ||||||
|   selector: '[my-dir]', |   selector: '[my-dir]', | ||||||
|   properties: {'dirProp':'elprop'} |   properties: {'dirProp':'elprop'} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user