Skip to content

Commit 41dc750

Browse files
authored
Merge pull request #407 from sveltejs/gh-398
prevent infinite loops caused by pathological component bindings
2 parents 8ff2de9 + 1780876 commit 41dc750

File tree

6 files changed

+165
-0
lines changed

6 files changed

+165
-0
lines changed

src/generators/dom/visitors/attributes/addComponentBinding.js

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default function createBinding ( generator, node, attribute, current, loc
4545
component._bindings.push( function () {
4646
if ( ${local.name}._torndown ) return;
4747
${local.name}.observe( '${attribute.name}', function ( value ) {
48+
if ( ${local.name}_updating ) return;
4849
${local.name}_updating = true;
4950
${setter}
5051
${local.name}_updating = false;
@@ -54,7 +55,9 @@ export default function createBinding ( generator, node, attribute, current, loc
5455

5556
local.update.addBlock( deindent`
5657
if ( !${local.name}_updating && ${dependencies.map( dependency => `'${dependency}' in changed` ).join( '||' )} ) {
58+
${local.name}_updating = true;
5759
${local.name}._set({ ${attribute.name}: ${snippet} });
60+
${local.name}_updating = false;
5861
}
5962
` );
6063
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<B bind:currentIdentifier />
2+
<B bind:currentIdentifier />
3+
4+
<script>
5+
import B from './B.html';
6+
7+
export default {
8+
components: {
9+
B
10+
}
11+
}
12+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{#each list as item}}
2+
<p>
3+
<C identifier="{{item}}" bind:currentIdentifier>
4+
{{item}}
5+
</C>
6+
</p>
7+
{{/each}}
8+
9+
<script>
10+
import C from './C.html';
11+
12+
export default {
13+
data: () => ({
14+
list: [1, 2, 3, 2, 1]
15+
}),
16+
components: {
17+
C
18+
}
19+
}
20+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<span
2+
on:click="toggle()"
3+
class="{{isCurrentlySelected ? 'selected' : ''}}"
4+
>
5+
{{yield}}
6+
</span>
7+
8+
<script>
9+
export default {
10+
computed: {
11+
isCurrentlySelected: (currentIdentifier, identifier) => currentIdentifier === identifier
12+
},
13+
methods: {
14+
toggle() {
15+
const isCurrentlySelected = this.get('isCurrentlySelected')
16+
17+
this.set({
18+
currentIdentifier: isCurrentlySelected ? null : this.get('identifier')
19+
})
20+
}
21+
}
22+
}
23+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
export default {
2+
html: `
3+
<p><span class=''>1</span></p>
4+
<p><span class='selected'>2</span></p>
5+
<p><span class=''>3</span></p>
6+
<p><span class='selected'>2</span></p>
7+
<p><span class=''>1</span></p>
8+
9+
<p><span class=''>1</span></p>
10+
<p><span class='selected'>2</span></p>
11+
<p><span class=''>3</span></p>
12+
<p><span class='selected'>2</span></p>
13+
<p><span class=''>1</span></p>
14+
15+
<p><span class=''>1</span></p>
16+
<p><span class='selected'>2</span></p>
17+
<p><span class=''>3</span></p>
18+
<p><span class='selected'>2</span></p>
19+
<p><span class=''>1</span></p>
20+
21+
<p><span class=''>1</span></p>
22+
<p><span class='selected'>2</span></p>
23+
<p><span class=''>3</span></p>
24+
<p><span class='selected'>2</span></p>
25+
<p><span class=''>1</span></p>
26+
`,
27+
28+
test ( assert, component, target, window ) {
29+
const click = new window.MouseEvent( 'click' );
30+
const spans = target.querySelectorAll( 'span' );
31+
32+
spans[0].dispatchEvent( click );
33+
34+
assert.equal( component.get( 'currentIdentifier' ), 1 );
35+
assert.htmlEqual( target.innerHTML, `
36+
<p><span class='selected'>1</span></p>
37+
<p><span class=''>2</span></p>
38+
<p><span class=''>3</span></p>
39+
<p><span class=''>2</span></p>
40+
<p><span class='selected'>1</span></p>
41+
42+
<p><span class='selected'>1</span></p>
43+
<p><span class=''>2</span></p>
44+
<p><span class=''>3</span></p>
45+
<p><span class=''>2</span></p>
46+
<p><span class='selected'>1</span></p>
47+
48+
<p><span class='selected'>1</span></p>
49+
<p><span class=''>2</span></p>
50+
<p><span class=''>3</span></p>
51+
<p><span class=''>2</span></p>
52+
<p><span class='selected'>1</span></p>
53+
54+
<p><span class='selected'>1</span></p>
55+
<p><span class=''>2</span></p>
56+
<p><span class=''>3</span></p>
57+
<p><span class=''>2</span></p>
58+
<p><span class='selected'>1</span></p>
59+
` );
60+
61+
spans[0].dispatchEvent( click );
62+
63+
assert.equal( component.get( 'currentIdentifier' ), null );
64+
assert.htmlEqual( target.innerHTML, `
65+
<p><span class=''>1</span></p>
66+
<p><span class=''>2</span></p>
67+
<p><span class=''>3</span></p>
68+
<p><span class=''>2</span></p>
69+
<p><span class=''>1</span></p>
70+
71+
<p><span class=''>1</span></p>
72+
<p><span class=''>2</span></p>
73+
<p><span class=''>3</span></p>
74+
<p><span class=''>2</span></p>
75+
<p><span class=''>1</span></p>
76+
77+
<p><span class=''>1</span></p>
78+
<p><span class=''>2</span></p>
79+
<p><span class=''>3</span></p>
80+
<p><span class=''>2</span></p>
81+
<p><span class=''>1</span></p>
82+
83+
<p><span class=''>1</span></p>
84+
<p><span class=''>2</span></p>
85+
<p><span class=''>3</span></p>
86+
<p><span class=''>2</span></p>
87+
<p><span class=''>1</span></p>
88+
` );
89+
}
90+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<A bind:currentIdentifier />
2+
<A bind:currentIdentifier />
3+
4+
<script>
5+
import A from './A.html';
6+
7+
export default {
8+
data() {
9+
return {
10+
currentIdentifier: 2
11+
}
12+
},
13+
components: {
14+
A
15+
}
16+
}
17+
</script>

0 commit comments

Comments
 (0)