diff --git a/src/generators/dom/visitors/Element/Binding.ts b/src/generators/dom/visitors/Element/Binding.ts index edc3767c0e..6be11e86a5 100644 --- a/src/generators/dom/visitors/Element/Binding.ts +++ b/src/generators/dom/visitors/Element/Binding.ts @@ -61,7 +61,7 @@ export default function visitBinding( type ); - let setter = getSetter(block, name, snippet, state.parentNode, attribute, dependencies, value); + let setter = getSetter(generator, block, name, snippet, state.parentNode, attribute, dependencies, value); let updateElement = `${state.parentNode}.${attribute.name} = ${snippet};`; const needsLock = !isReadOnly && node.name !== 'input' || !/radio|checkbox|range|color/.test(type); // TODO others? @@ -290,6 +290,7 @@ function getBindingGroup(generator: DomGenerator, value: Node) { } function getSetter( + generator: DomGenerator, block: Block, name: string, snippet: string, @@ -319,6 +320,15 @@ function getSetter( } if (attribute.value.type === 'MemberExpression') { + // This is a little confusing, and should probably be tidied up + // at some point. It addresses a tricky bug (#893), wherein + // Svelte tries to `set()` a computed property, which throws an + // error in dev mode. a) it's possible that we should be + // replacing computations with *their* dependencies, and b) + // we should probably populate `generator.readonly` sooner so + // that we don't have to do the `.some()` here + dependencies = dependencies.filter(prop => !generator.computations.some(computation => computation.key === prop)); + return deindent` var state = #component.get(); ${snippet} = ${value}; diff --git a/test/runtime/samples/binding-indirect-computed/_config.js b/test/runtime/samples/binding-indirect-computed/_config.js new file mode 100644 index 0000000000..f7ac841f21 --- /dev/null +++ b/test/runtime/samples/binding-indirect-computed/_config.js @@ -0,0 +1,32 @@ +export default { + dev: true, + + html: ` + + `, + + test(assert, component, target, window) { + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + + assert.equal(component.get('selected').letter, 'B'); + assert.htmlEqual(target.innerHTML, ` + + + B + `); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/binding-indirect-computed/main.html b/test/runtime/samples/binding-indirect-computed/main.html new file mode 100644 index 0000000000..88e638bf30 --- /dev/null +++ b/test/runtime/samples/binding-indirect-computed/main.html @@ -0,0 +1,27 @@ + + +{{selected.letter}} + + \ No newline at end of file