X Tutup
Skip to content

Commit 8499cf8

Browse files
committed
fix(shadow_dom): redistribute light dom when a dynamic component is attached.
Fixes angular#1077 Closes angular#1315
1 parent daf0f47 commit 8499cf8

File tree

5 files changed

+138
-23
lines changed

5 files changed

+138
-23
lines changed

modules/angular2/src/render/dom/view/view.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ export class RenderView {
6969
this.componentChildViews[elementIndex] = childView;
7070
if (this._hydrated) {
7171
childView.hydrate(lightDom);
72+
if (isPresent(lightDom)) {
73+
lightDom.redistribute();
74+
}
7275
}
7376
}
7477

modules/angular2/test/render/dom/direct_dom_renderer_integration_spec.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {IntegrationTestbed, LoggingEventDispatcher, FakeEvent} from './integrati
2121

2222
export function main() {
2323
describe('DirectDomRenderer integration', () => {
24-
var testbed, renderer, eventPlugin, compile, rootEl;
24+
var testbed, renderer, eventPlugin, compileRoot, rootEl;
2525

2626
beforeEach(() => {
2727
rootEl = el('<div></div>');
@@ -36,7 +36,7 @@ export function main() {
3636
});
3737
renderer = testbed.renderer;
3838
eventPlugin = testbed.eventPlugin;
39-
compile = (rootEl, componentId) => testbed.compile(rootEl, componentId);
39+
compileRoot = (rootEl, componentId) => testbed.compileRoot(rootEl, componentId);
4040
}
4141

4242
it('should create root views while using the given elements in place', inject([AsyncTestCompleter], (async) => {
@@ -93,7 +93,7 @@ export function main() {
9393
directives: []
9494
})]
9595
});
96-
compile(rootEl, 'someComponent').then( (rootProtoView) => {
96+
compileRoot(rootEl, 'someComponent').then( (rootProtoView) => {
9797
var viewRefs = renderer.createView(rootProtoView.render);
9898
renderer.setText(viewRefs[1], 0, 'hello');
9999
expect(rootEl).toHaveText('hello');
@@ -109,7 +109,7 @@ export function main() {
109109
directives: []
110110
})]
111111
});
112-
compile(rootEl, 'someComponent').then( (rootProtoView) => {
112+
compileRoot(rootEl, 'someComponent').then( (rootProtoView) => {
113113
var viewRefs = renderer.createView(rootProtoView.render);
114114
renderer.setElementProperty(viewRefs[1], 0, 'value', 'hello');
115115
expect(DOM.childNodes(rootEl)[0].value).toEqual('hello');
@@ -125,7 +125,7 @@ export function main() {
125125
directives: []
126126
})]
127127
});
128-
compile(rootEl, 'someComponent').then( (rootProtoView) => {
128+
compileRoot(rootEl, 'someComponent').then( (rootProtoView) => {
129129
var viewRef = renderer.createView(rootProtoView.render)[1];
130130
var vcProtoViewRef = rootProtoView.elementBinders[0]
131131
.nestedProtoView.elementBinders[0].nestedProtoView.render;
@@ -151,7 +151,7 @@ export function main() {
151151
})],
152152
viewCacheCapacity: 2
153153
});
154-
compile(rootEl, 'someComponent').then( (rootProtoView) => {
154+
compileRoot(rootEl, 'someComponent').then( (rootProtoView) => {
155155
var vcProtoViewRef = rootProtoView.elementBinders[0]
156156
.nestedProtoView.elementBinders[0].nestedProtoView.render;
157157

@@ -176,7 +176,7 @@ export function main() {
176176
directives: []
177177
})]
178178
});
179-
compile(rootEl, 'someComponent').then( (rootProtoView) => {
179+
compileRoot(rootEl, 'someComponent').then( (rootProtoView) => {
180180
var viewRef = renderer.createView(rootProtoView.render)[1];
181181
var dispatcher = new LoggingEventDispatcher();
182182
renderer.setEventDispatcher(viewRef, dispatcher);

modules/angular2/test/render/dom/integration_testbed.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class IntegrationTestbed {
4848
this.renderer = new DirectDomRenderer(compiler, viewFactory, shadowDomStrategy);
4949
}
5050

51-
compile(rootEl, componentId):Promise<ProtoViewDto> {
51+
compileRoot(rootEl, componentId):Promise<ProtoViewDto> {
5252
return this.renderer.createRootProtoView(rootEl, componentId).then( (rootProtoView) => {
5353
return this._compileNestedProtoViews(rootProtoView, [
5454
new DirectiveMetadata({
@@ -59,9 +59,13 @@ export class IntegrationTestbed {
5959
});
6060
}
6161

62-
_compile(template):Promise<ProtoViewDto> {
63-
return this.renderer.compile(template).then( (protoView) => {
64-
return this._compileNestedProtoViews(protoView, template.directives);
62+
compile(componentId):Promise<ProtoViewDto> {
63+
var childTemplate = MapWrapper.get(this._templates, componentId);
64+
if (isBlank(childTemplate)) {
65+
throw new BaseException(`No template for component ${componentId}`);
66+
}
67+
return this.renderer.compile(childTemplate).then( (protoView) => {
68+
return this._compileNestedProtoViews(protoView, childTemplate.directives);
6569
});
6670
}
6771

@@ -80,9 +84,11 @@ export class IntegrationTestbed {
8084
if (isPresent(nestedComponentId)) {
8185
var childTemplate = MapWrapper.get(this._templates, nestedComponentId);
8286
if (isBlank(childTemplate)) {
83-
throw new BaseException(`Could not find template for ${nestedComponentId}!`);
87+
// dynamic component
88+
ListWrapper.push(childComponentRenderPvRefs, null);
89+
} else {
90+
nestedCall = this.compile(nestedComponentId);
8491
}
85-
nestedCall = this._compile(childTemplate);
8692
} else if (isPresent(elementBinder.nestedProtoView)) {
8793
nestedCall = this._compileNestedProtoViews(elementBinder.nestedProtoView, directives);
8894
}

modules/angular2/test/render/dom/shadow_dom_emulation_integration_spec.js

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,16 @@ export function main() {
5252

5353
describe(`${name} shadow dom strategy`, () => {
5454

55-
var testbed, renderer, rootEl, compile;
55+
var testbed, renderer, rootEl, compile, compileRoot;
5656

5757
function createRenderer({templates}) {
5858
testbed = new IntegrationTestbed({
5959
shadowDomStrategy: strategyFactory(),
6060
templates: ListWrapper.concat(templates, componentTemplates)
6161
});
6262
renderer = testbed.renderer;
63-
compile = (rootEl, componentId) => testbed.compile(rootEl, componentId);
63+
compileRoot = (rootEl, componentId) => testbed.compileRoot(rootEl, componentId);
64+
compile = (componentId) => testbed.compile(componentId);
6465
}
6566

6667
beforeEach( () => {
@@ -77,7 +78,7 @@ export function main() {
7778
directives: [simple]
7879
})]
7980
});
80-
compile(rootEl, 'main').then( (pv) => {
81+
compileRoot(rootEl, 'main').then( (pv) => {
8182
renderer.createView(pv.render);
8283

8384
expect(rootEl).toHaveText('SIMPLE(A)');
@@ -86,6 +87,29 @@ export function main() {
8687
});
8788
}));
8889

90+
it('should support dynamic components', inject([AsyncTestCompleter], (async) => {
91+
createRenderer({
92+
templates: [new ViewDefinition({
93+
componentId: 'main',
94+
template: '<dynamic>' +
95+
'<div>A</div>' +
96+
'</dynamic>',
97+
directives: [dynamicComponent]
98+
})]
99+
});
100+
compileRoot(rootEl, 'main').then( (rootPv) => {
101+
compile('simple').then( (simplePv) => {
102+
var views = renderer.createView(rootPv.render);
103+
var simpleViews = renderer.createView(simplePv.render);
104+
renderer.setDynamicComponentView(views[1], 0, simpleViews[0]);
105+
106+
expect(rootEl).toHaveText('SIMPLE(A)');
107+
108+
async.done();
109+
});
110+
});
111+
}));
112+
89113
it('should support multiple content tags', inject([AsyncTestCompleter], (async) => {
90114
createRenderer({
91115
templates: [new ViewDefinition({
@@ -98,7 +122,7 @@ export function main() {
98122
directives: [multipleContentTagsComponent]
99123
})]
100124
});
101-
compile(rootEl, 'main').then( (pv) => {
125+
compileRoot(rootEl, 'main').then( (pv) => {
102126
renderer.createView(pv.render);
103127

104128
expect(rootEl).toHaveText('(A, BC)');
@@ -118,7 +142,7 @@ export function main() {
118142
directives: [multipleContentTagsComponent]
119143
})]
120144
});
121-
compile(rootEl, 'main').then( (pv) => {
145+
compileRoot(rootEl, 'main').then( (pv) => {
122146
renderer.createView(pv.render);
123147

124148
expect(rootEl).toHaveText('(, BAC)');
@@ -138,7 +162,7 @@ export function main() {
138162
directives: [multipleContentTagsComponent, manualViewportDirective]
139163
})]
140164
});
141-
compile(rootEl, 'main').then( (pv) => {
165+
compileRoot(rootEl, 'main').then( (pv) => {
142166
var viewRefs = renderer.createView(pv.render);
143167
var vcRef = new ViewContainerRef(viewRefs[1], 1);
144168
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
@@ -170,7 +194,7 @@ export function main() {
170194
directives: [multipleContentTagsComponent, manualViewportDirective]
171195
})]
172196
});
173-
compile(rootEl, 'main').then( (pv) => {
197+
compileRoot(rootEl, 'main').then( (pv) => {
174198
var viewRefs = renderer.createView(pv.render);
175199
var vcRef = new ViewContainerRef(viewRefs[1], 1);
176200
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
@@ -202,7 +226,7 @@ export function main() {
202226
directives: [outerWithIndirectNestedComponent]
203227
})]
204228
});
205-
compile(rootEl, 'main').then( (pv) => {
229+
compileRoot(rootEl, 'main').then( (pv) => {
206230
renderer.createView(pv.render);
207231

208232
expect(rootEl).toHaveText('OUTER(SIMPLE(AB))');
@@ -223,7 +247,7 @@ export function main() {
223247
directives: [outerComponent, manualViewportDirective]
224248
})]
225249
});
226-
compile(rootEl, 'main').then( (pv) => {
250+
compileRoot(rootEl, 'main').then( (pv) => {
227251
var viewRefs = renderer.createView(pv.render);
228252
var vcRef = new ViewContainerRef(viewRefs[1], 1);
229253
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
@@ -251,7 +275,7 @@ export function main() {
251275
directives: [conditionalContentComponent]
252276
})]
253277
});
254-
compile(rootEl, 'main').then( (pv) => {
278+
compileRoot(rootEl, 'main').then( (pv) => {
255279
var viewRefs = renderer.createView(pv.render);
256280
var vcRef = new ViewContainerRef(viewRefs[2], 0);
257281
var vcProtoViewRef = pv.elementBinders[0].nestedProtoView
@@ -302,6 +326,12 @@ var simple = new DirectiveMetadata({
302326
type: DirectiveMetadata.COMPONENT_TYPE
303327
});
304328

329+
var dynamicComponent = new DirectiveMetadata({
330+
selector: 'dynamic',
331+
id: 'dynamic',
332+
type: DirectiveMetadata.COMPONENT_TYPE
333+
});
334+
305335
var multipleContentTagsComponent = new DirectiveMetadata({
306336
selector: 'multiple-content-tags',
307337
id: 'multiple-content-tags',
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib';
2+
3+
import {ListWrapper} from 'angular2/src/facade/collection';
4+
5+
import {RenderView} from 'angular2/src/render/dom/view/view';
6+
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
7+
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
8+
9+
export function main() {
10+
11+
function createView() {
12+
var proto = null;
13+
var rootNodes = [el('<div></div>')];
14+
var boundTextNodes = [];
15+
var boundElements = [el('<div></div>')];
16+
var viewContainers = [];
17+
var contentTags = [];
18+
return new RenderView(proto, rootNodes,
19+
boundTextNodes, boundElements, viewContainers, contentTags);
20+
}
21+
22+
function createShadowDomStrategy(log) {
23+
return new FakeShadowDomStrategy(log);
24+
}
25+
26+
describe('RenderView', () => {
27+
var log, strategy;
28+
29+
beforeEach( () => {
30+
log = [];
31+
strategy = createShadowDomStrategy(log);
32+
});
33+
34+
describe('setComponentView', () => {
35+
36+
it('should redistribute when a component is added to a hydrated view', () => {
37+
var hostView = createView();
38+
var childView = createView();
39+
hostView.hydrate(null);
40+
hostView.setComponentView(strategy, 0, childView);
41+
expect(log[0]).toEqual(['redistribute']);
42+
});
43+
44+
it('should not redistribute when a component is added to a dehydrated view', () => {
45+
var hostView = createView();
46+
var childView = createView();
47+
hostView.setComponentView(strategy, 0, childView);
48+
expect(log).toEqual([]);
49+
});
50+
51+
});
52+
53+
});
54+
}
55+
56+
class FakeShadowDomStrategy extends ShadowDomStrategy {
57+
log;
58+
constructor(log) {
59+
super();
60+
this.log = log;
61+
}
62+
constructLightDom(lightDomView:RenderView, shadowDomView:RenderView, element): LightDom {
63+
return new FakeLightDom(this.log, lightDomView, shadowDomView, element);
64+
}
65+
}
66+
67+
class FakeLightDom extends LightDom {
68+
log;
69+
constructor(log, lightDomView:RenderView, shadowDomView:RenderView, element) {
70+
super(lightDomView, shadowDomView, element);
71+
this.log = log;
72+
}
73+
redistribute() {
74+
ListWrapper.push(this.log, ['redistribute']);
75+
}
76+
}

0 commit comments

Comments
 (0)
X Tutup