bind to store values in simple cases - fixes #1997

pull/2010/head
Richard Harris 6 years ago
parent 9f800fb914
commit bcbe0a58b2

@ -221,6 +221,17 @@ function getEventHandler(
snippet: string
) {
const value = getValueFromDom(renderer, binding.parent, binding);
const store = binding.object[0] === '$' ? binding.object.slice(1) : null;
if (store && binding.node.expression.node.type === 'MemberExpression') {
// TODO is there a way around this? Mutating an object doesn't work,
// because stores check for referential equality (i.e. immutable data).
// But we can't safely or easily clone objects. So for now, we bail
renderer.component.error(binding.node.expression.node.property, {
code: 'invalid-store-binding',
message: 'Cannot bind to a nested property of a store'
});
}
if (binding.node.isContextual) {
let tail = '';
@ -233,15 +244,21 @@ function getEventHandler(
return {
usesContext: true,
mutation: `${snippet}${tail} = ${value};`,
mutation: store
? `${store}.set(${value});`
: `${snippet}${tail} = ${value};`,
contextual_dependencies: new Set([object, property])
};
}
const mutation = store
? `${store}.set(${value});`
: `${snippet} = ${value};`;
if (binding.node.expression.node.type === 'MemberExpression') {
return {
usesContext: binding.node.expression.usesContext,
mutation: `${snippet} = ${value};`,
mutation,
contextual_dependencies: binding.node.expression.contextual_dependencies,
snippet
};
@ -249,7 +266,7 @@ function getEventHandler(
return {
usesContext: false,
mutation: `${snippet} = ${value};`,
mutation,
contextual_dependencies: new Set()
};
}

@ -456,7 +456,7 @@ export default class ElementWrapper extends Wrapper {
this.renderer.component.partly_hoisted.push(deindent`
function ${handler}(${contextual_dependencies.size > 0 ? `{ ${[...contextual_dependencies].join(', ')} }` : ``}) {
${group.bindings.map(b => b.handler.mutation)}
${Array.from(dependencies).map(dep => `$$invalidate('${dep}', ${dep});`)}
${Array.from(dependencies).filter(dep => dep[0] !== '$').map(dep => `$$invalidate('${dep}', ${dep});`)}
}
`);

@ -0,0 +1,5 @@
export default {
error(assert, err) {
assert.equal(err.message, `Cannot bind to a nested property of a store`);
}
};

@ -0,0 +1,8 @@
<script>
import { writable } from 'svelte/store';
export const user = writable({ name: 'world' });
</script>
<input bind:value={$user.name}>
<p>hello {$user.name}</p>

@ -0,0 +1,41 @@
export default {
html: `
<input>
<p>hello world</p>
`,
ssrHtml: `
<input value="world">
<p>hello world</p>
`,
async test({ assert, component, target, window }) {
const input = target.querySelector('input');
assert.equal(input.value, 'world');
const event = new window.Event('input');
const names = [];
const unsubscribe = component.name.subscribe(name => {
names.push(name);
});
input.value = 'everybody';
await input.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<input>
<p>hello everybody</p>
`);
await component.name.set('goodbye');
assert.equal(input.value, 'goodbye');
assert.htmlEqual(target.innerHTML, `
<input>
<p>hello goodbye</p>
`);
assert.deepEqual(names, ['world', 'everybody', 'goodbye']);
unsubscribe();
},
};

@ -0,0 +1,8 @@
<script>
import { writable } from 'svelte/store';
export const name = writable('world');
</script>
<input bind:value={$name}>
<p>hello {$name}</p>
Loading…
Cancel
Save