fix(shadow_dom): redistribute light dom when a dynamic component is attached.
Fixes #1077 Closes #1315
This commit is contained in:
		
							parent
							
								
									daf0f472b3
								
							
						
					
					
						commit
						8499cf84c3
					
				
							
								
								
									
										3
									
								
								modules/angular2/src/render/dom/view/view.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								modules/angular2/src/render/dom/view/view.js
									
									
									
									
										vendored
									
									
								
							| @ -69,6 +69,9 @@ export class RenderView { | ||||
|     this.componentChildViews[elementIndex] = childView; | ||||
|     if (this._hydrated) { | ||||
|       childView.hydrate(lightDom); | ||||
|       if (isPresent(lightDom)) { | ||||
|         lightDom.redistribute(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -21,7 +21,7 @@ import {IntegrationTestbed, LoggingEventDispatcher, FakeEvent} from './integrati | ||||
| 
 | ||||
| export function main() { | ||||
|   describe('DirectDomRenderer integration', () => { | ||||
|     var testbed, renderer, eventPlugin, compile, rootEl; | ||||
|     var testbed, renderer, eventPlugin, compileRoot, rootEl; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       rootEl = el('<div></div>'); | ||||
| @ -36,7 +36,7 @@ export function main() { | ||||
|       }); | ||||
|       renderer = testbed.renderer; | ||||
|       eventPlugin = testbed.eventPlugin; | ||||
|       compile = (rootEl, componentId) => testbed.compile(rootEl, componentId); | ||||
|       compileRoot = (rootEl, componentId) => testbed.compileRoot(rootEl, componentId); | ||||
|     } | ||||
| 
 | ||||
|     it('should create root views while using the given elements in place', inject([AsyncTestCompleter], (async) => { | ||||
| @ -93,7 +93,7 @@ export function main() { | ||||
|           directives: [] | ||||
|         })] | ||||
|       }); | ||||
|       compile(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|       compileRoot(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|         var viewRefs = renderer.createView(rootProtoView.render); | ||||
|         renderer.setText(viewRefs[1], 0, 'hello'); | ||||
|         expect(rootEl).toHaveText('hello'); | ||||
| @ -109,7 +109,7 @@ export function main() { | ||||
|           directives: [] | ||||
|         })] | ||||
|       }); | ||||
|       compile(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|       compileRoot(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|         var viewRefs = renderer.createView(rootProtoView.render); | ||||
|         renderer.setElementProperty(viewRefs[1], 0, 'value', 'hello'); | ||||
|         expect(DOM.childNodes(rootEl)[0].value).toEqual('hello'); | ||||
| @ -125,7 +125,7 @@ export function main() { | ||||
|           directives: [] | ||||
|         })] | ||||
|       }); | ||||
|       compile(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|       compileRoot(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|         var viewRef = renderer.createView(rootProtoView.render)[1]; | ||||
|         var vcProtoViewRef = rootProtoView.elementBinders[0] | ||||
|           .nestedProtoView.elementBinders[0].nestedProtoView.render; | ||||
| @ -151,7 +151,7 @@ export function main() { | ||||
|         })], | ||||
|         viewCacheCapacity: 2 | ||||
|       }); | ||||
|       compile(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|       compileRoot(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|         var vcProtoViewRef = rootProtoView.elementBinders[0] | ||||
|           .nestedProtoView.elementBinders[0].nestedProtoView.render; | ||||
| 
 | ||||
| @ -176,7 +176,7 @@ export function main() { | ||||
|           directives: [] | ||||
|         })] | ||||
|       }); | ||||
|       compile(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|       compileRoot(rootEl, 'someComponent').then( (rootProtoView) => { | ||||
|         var viewRef = renderer.createView(rootProtoView.render)[1]; | ||||
|         var dispatcher = new LoggingEventDispatcher(); | ||||
|         renderer.setEventDispatcher(viewRef, dispatcher); | ||||
|  | ||||
| @ -48,7 +48,7 @@ export class IntegrationTestbed { | ||||
|     this.renderer = new DirectDomRenderer(compiler, viewFactory, shadowDomStrategy); | ||||
|   } | ||||
| 
 | ||||
|   compile(rootEl, componentId):Promise<ProtoViewDto> { | ||||
|   compileRoot(rootEl, componentId):Promise<ProtoViewDto> { | ||||
|     return this.renderer.createRootProtoView(rootEl, componentId).then( (rootProtoView) => { | ||||
|       return this._compileNestedProtoViews(rootProtoView, [ | ||||
|         new DirectiveMetadata({ | ||||
| @ -59,9 +59,13 @@ export class IntegrationTestbed { | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   _compile(template):Promise<ProtoViewDto> { | ||||
|     return this.renderer.compile(template).then( (protoView) => { | ||||
|       return this._compileNestedProtoViews(protoView, template.directives); | ||||
|   compile(componentId):Promise<ProtoViewDto> { | ||||
|     var childTemplate = MapWrapper.get(this._templates, componentId); | ||||
|     if (isBlank(childTemplate)) { | ||||
|       throw new BaseException(`No template for component ${componentId}`); | ||||
|     } | ||||
|     return this.renderer.compile(childTemplate).then( (protoView) => { | ||||
|       return this._compileNestedProtoViews(protoView, childTemplate.directives); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
| @ -80,9 +84,11 @@ export class IntegrationTestbed { | ||||
|       if (isPresent(nestedComponentId)) { | ||||
|         var childTemplate = MapWrapper.get(this._templates, nestedComponentId); | ||||
|         if (isBlank(childTemplate)) { | ||||
|           throw new BaseException(`Could not find template for ${nestedComponentId}!`); | ||||
|           // dynamic component
 | ||||
|           ListWrapper.push(childComponentRenderPvRefs, null); | ||||
|         } else { | ||||
|           nestedCall = this.compile(nestedComponentId); | ||||
|         } | ||||
|         nestedCall = this._compile(childTemplate); | ||||
|       } else if (isPresent(elementBinder.nestedProtoView)) { | ||||
|         nestedCall = this._compileNestedProtoViews(elementBinder.nestedProtoView, directives); | ||||
|       } | ||||
|  | ||||
| @ -52,7 +52,7 @@ export function main() { | ||||
| 
 | ||||
|       describe(`${name} shadow dom strategy`, () => { | ||||
| 
 | ||||
|         var testbed, renderer, rootEl, compile; | ||||
|         var testbed, renderer, rootEl, compile, compileRoot; | ||||
| 
 | ||||
|         function createRenderer({templates}) { | ||||
|           testbed = new IntegrationTestbed({ | ||||
| @ -60,7 +60,8 @@ export function main() { | ||||
|             templates: ListWrapper.concat(templates, componentTemplates) | ||||
|           }); | ||||
|           renderer = testbed.renderer; | ||||
|           compile = (rootEl, componentId) => testbed.compile(rootEl, componentId); | ||||
|           compileRoot = (rootEl, componentId) => testbed.compileRoot(rootEl, componentId); | ||||
|           compile = (componentId) => testbed.compile(componentId); | ||||
|         } | ||||
| 
 | ||||
|         beforeEach( () => { | ||||
| @ -77,7 +78,7 @@ export function main() { | ||||
|               directives: [simple] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             renderer.createView(pv.render); | ||||
| 
 | ||||
|             expect(rootEl).toHaveText('SIMPLE(A)'); | ||||
| @ -86,6 +87,29 @@ export function main() { | ||||
|           }); | ||||
|         })); | ||||
| 
 | ||||
|         it('should support dynamic components', inject([AsyncTestCompleter], (async) => { | ||||
|           createRenderer({ | ||||
|             templates: [new ViewDefinition({ | ||||
|               componentId: 'main', | ||||
|               template: '<dynamic>' + | ||||
|                 '<div>A</div>' + | ||||
|                 '</dynamic>', | ||||
|               directives: [dynamicComponent] | ||||
|             })] | ||||
|           }); | ||||
|           compileRoot(rootEl, 'main').then( (rootPv) => { | ||||
|             compile('simple').then( (simplePv) => { | ||||
|               var views = renderer.createView(rootPv.render); | ||||
|               var simpleViews = renderer.createView(simplePv.render); | ||||
|               renderer.setDynamicComponentView(views[1], 0, simpleViews[0]); | ||||
| 
 | ||||
|               expect(rootEl).toHaveText('SIMPLE(A)'); | ||||
| 
 | ||||
|               async.done(); | ||||
|             }); | ||||
|           }); | ||||
|         })); | ||||
| 
 | ||||
|         it('should support multiple content tags', inject([AsyncTestCompleter], (async) => { | ||||
|           createRenderer({ | ||||
|             templates: [new ViewDefinition({ | ||||
| @ -98,7 +122,7 @@ export function main() { | ||||
|               directives: [multipleContentTagsComponent] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             renderer.createView(pv.render); | ||||
| 
 | ||||
|             expect(rootEl).toHaveText('(A, BC)'); | ||||
| @ -118,7 +142,7 @@ export function main() { | ||||
|               directives: [multipleContentTagsComponent] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             renderer.createView(pv.render); | ||||
| 
 | ||||
|             expect(rootEl).toHaveText('(, BAC)'); | ||||
| @ -138,7 +162,7 @@ export function main() { | ||||
|               directives: [multipleContentTagsComponent, manualViewportDirective] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             var viewRefs = renderer.createView(pv.render); | ||||
|             var vcRef = new ViewContainerRef(viewRefs[1], 1); | ||||
|             var vcProtoViewRef = pv.elementBinders[0].nestedProtoView | ||||
| @ -170,7 +194,7 @@ export function main() { | ||||
|               directives: [multipleContentTagsComponent, manualViewportDirective] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             var viewRefs = renderer.createView(pv.render); | ||||
|             var vcRef = new ViewContainerRef(viewRefs[1], 1); | ||||
|             var vcProtoViewRef = pv.elementBinders[0].nestedProtoView | ||||
| @ -202,7 +226,7 @@ export function main() { | ||||
|               directives: [outerWithIndirectNestedComponent] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             renderer.createView(pv.render); | ||||
| 
 | ||||
|             expect(rootEl).toHaveText('OUTER(SIMPLE(AB))'); | ||||
| @ -223,7 +247,7 @@ export function main() { | ||||
|               directives: [outerComponent, manualViewportDirective] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             var viewRefs = renderer.createView(pv.render); | ||||
|             var vcRef = new ViewContainerRef(viewRefs[1], 1); | ||||
|             var vcProtoViewRef = pv.elementBinders[0].nestedProtoView | ||||
| @ -251,7 +275,7 @@ export function main() { | ||||
|               directives: [conditionalContentComponent] | ||||
|             })] | ||||
|           }); | ||||
|           compile(rootEl, 'main').then( (pv) => { | ||||
|           compileRoot(rootEl, 'main').then( (pv) => { | ||||
|             var viewRefs = renderer.createView(pv.render); | ||||
|             var vcRef = new ViewContainerRef(viewRefs[2], 0); | ||||
|             var vcProtoViewRef = pv.elementBinders[0].nestedProtoView | ||||
| @ -302,6 +326,12 @@ var simple = new DirectiveMetadata({ | ||||
|   type: DirectiveMetadata.COMPONENT_TYPE | ||||
| }); | ||||
| 
 | ||||
| var dynamicComponent = new DirectiveMetadata({ | ||||
|   selector: 'dynamic', | ||||
|   id: 'dynamic', | ||||
|   type: DirectiveMetadata.COMPONENT_TYPE | ||||
| }); | ||||
| 
 | ||||
| var multipleContentTagsComponent = new DirectiveMetadata({ | ||||
|   selector: 'multiple-content-tags', | ||||
|   id: 'multiple-content-tags', | ||||
|  | ||||
							
								
								
									
										76
									
								
								modules/angular2/test/render/dom/view/view_spec.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								modules/angular2/test/render/dom/view/view_spec.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib'; | ||||
| 
 | ||||
| import {ListWrapper} from 'angular2/src/facade/collection'; | ||||
| 
 | ||||
| import {RenderView} from 'angular2/src/render/dom/view/view'; | ||||
| import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy'; | ||||
| import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom'; | ||||
| 
 | ||||
| export function main() { | ||||
| 
 | ||||
|   function createView() { | ||||
|     var proto = null; | ||||
|     var rootNodes = [el('<div></div>')]; | ||||
|     var boundTextNodes = []; | ||||
|     var boundElements = [el('<div></div>')]; | ||||
|     var viewContainers = []; | ||||
|     var contentTags = []; | ||||
|     return new RenderView(proto, rootNodes, | ||||
|       boundTextNodes, boundElements, viewContainers, contentTags); | ||||
|   } | ||||
| 
 | ||||
|   function createShadowDomStrategy(log) { | ||||
|     return new FakeShadowDomStrategy(log); | ||||
|   } | ||||
| 
 | ||||
|   describe('RenderView', () => { | ||||
|     var log, strategy; | ||||
| 
 | ||||
|     beforeEach( () => { | ||||
|       log = []; | ||||
|       strategy = createShadowDomStrategy(log); | ||||
|     }); | ||||
| 
 | ||||
|     describe('setComponentView', () => { | ||||
| 
 | ||||
|       it('should redistribute when a component is added to a hydrated view', () => { | ||||
|         var hostView = createView(); | ||||
|         var childView = createView(); | ||||
|         hostView.hydrate(null); | ||||
|         hostView.setComponentView(strategy, 0, childView); | ||||
|         expect(log[0]).toEqual(['redistribute']); | ||||
|       }); | ||||
| 
 | ||||
|       it('should not redistribute when a component is added to a dehydrated view', () => { | ||||
|         var hostView = createView(); | ||||
|         var childView = createView(); | ||||
|         hostView.setComponentView(strategy, 0, childView); | ||||
|         expect(log).toEqual([]); | ||||
|       }); | ||||
| 
 | ||||
|     }); | ||||
| 
 | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| class FakeShadowDomStrategy extends ShadowDomStrategy { | ||||
|   log; | ||||
|   constructor(log) { | ||||
|     super(); | ||||
|     this.log = log; | ||||
|   } | ||||
|   constructLightDom(lightDomView:RenderView, shadowDomView:RenderView, element): LightDom { | ||||
|     return new FakeLightDom(this.log, lightDomView, shadowDomView, element); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class FakeLightDom extends LightDom { | ||||
|   log; | ||||
|   constructor(log, lightDomView:RenderView, shadowDomView:RenderView, element) { | ||||
|     super(lightDomView, shadowDomView, element); | ||||
|     this.log = log; | ||||
|   } | ||||
|   redistribute() { | ||||
|     ListWrapper.push(this.log, ['redistribute']); | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user