fix indirect bindings on elements with spreads (#4398)

pull/4404/head
Conduitry 5 years ago committed by GitHub
parent c3232826d4
commit b6d80f485a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,9 @@
# Svelte changelog
## Unreleased
* Fix indirect bindings involving elements with spreads ([#3680](https://github.com/sveltejs/svelte/issues/3680))
## 3.18.2
* Fix binding to module-level variables ([#4086](https://github.com/sveltejs/svelte/issues/4086))

@ -39,20 +39,25 @@ export default class AttributeWrapper {
}
}
render(block: Block) {
is_indirectly_bound_value() {
const element = this.parent;
const name = fix_attribute_casing(this.node.name);
const metadata = this.get_metadata();
const is_indirectly_bound_value =
name === 'value' &&
return name === 'value' &&
(element.node.name === 'option' || // TODO check it's actually bound
(element.node.name === 'input' &&
element.node.bindings.find(
element.node.bindings.some(
(binding) =>
/checked|group/.test(binding.name)
)));
}
render(block: Block) {
const element = this.parent;
const name = fix_attribute_casing(this.node.name);
const metadata = this.get_metadata();
const is_indirectly_bound_value = this.is_indirectly_bound_value();
const property_name = is_indirectly_bound_value
? '__value'

@ -679,10 +679,10 @@ export default class ElementWrapper extends Wrapper {
updates.push(condition ? x`${condition} && ${snippet}` : snippet);
} else {
const metadata = attr.get_metadata();
const snippet = x`{ ${
(metadata && metadata.property_name) ||
fix_attribute_casing(attr.node.name)
}: ${attr.get_value(block)} }`;
const name = attr.is_indirectly_bound_value()
? '__value'
: (metadata && metadata.property_name) || fix_attribute_casing(attr.node.name);
const snippet = x`{ ${name}: ${attr.get_value(block)} }`;
initial_props.push(snippet);
updates.push(condition ? x`${condition} && ${snippet}` : snippet);

@ -98,7 +98,7 @@ export function set_attributes(node: Element & ElementCSSInlineStyle, attributes
node.removeAttribute(key);
} else if (key === 'style') {
node.style.cssText = attributes[key];
} else if (descriptors[key] && descriptors[key].set) {
} else if (key === '__value' || descriptors[key] && descriptors[key].set) {
node[key] = attributes[key];
} else {
attr(node, key, attributes[key]);

@ -0,0 +1,44 @@
export default {
skip_if_ssr: true,
async test({ assert, component, target, window }) {
const event = new window.MouseEvent('click');
const [radio1, radio2, radio3] = target.querySelectorAll('input[type=radio]');
assert.ok(!radio1.checked);
assert.ok(radio2.checked);
assert.ok(!radio3.checked);
component.radio = 'radio1';
assert.ok(radio1.checked);
assert.ok(!radio2.checked);
assert.ok(!radio3.checked);
await radio3.dispatchEvent(event);
assert.equal(component.radio, 'radio3');
assert.ok(!radio1.checked);
assert.ok(!radio2.checked);
assert.ok(radio3.checked);
const [check1, check2, check3] = target.querySelectorAll('input[type=checkbox]');
assert.ok(!check1.checked);
assert.ok(check2.checked);
assert.ok(!check3.checked);
component.check = ['check1', 'check2'];
assert.ok(check1.checked);
assert.ok(check2.checked);
assert.ok(!check3.checked);
await check3.dispatchEvent(event);
assert.deepEqual(component.check, ['check1', 'check2', 'check3']);
assert.ok(check1.checked);
assert.ok(check2.checked);
assert.ok(check3.checked);
}
};

@ -0,0 +1,12 @@
<script>
export let radio = 'radio2';
export let check = ['check2'];
</script>
<input type='radio' bind:group={radio} value='radio1' {...{}}>
<input type='radio' bind:group={radio} value='radio2' {...{}}>
<input type='radio' bind:group={radio} value='radio3' {...{}}>
<input type='checkbox' bind:group={check} value='check1' {...{}}>
<input type='checkbox' bind:group={check} value='check2' {...{}}>
<input type='checkbox' bind:group={check} value='check3' {...{}}>
Loading…
Cancel
Save