binding dependencies

pull/1746/head
Rich Harris 8 years ago
parent 10255a980e
commit ddf09b9edf

@ -22,6 +22,7 @@ export default class BindingWrapper {
element: ElementWrapper;
binding: Binding;
events: string[];
dependencies: Set<string>;
usesStore: boolean;
needsLock: boolean;
@ -39,7 +40,7 @@ export default class BindingWrapper {
isReadOnly: boolean;
isReadOnlyMediaAttribute: boolean;
constructor(element: ElementWrapper, binding: Binding) {
constructor(block: Block, element: ElementWrapper, binding: Binding) {
this.element = element;
this.binding = binding;
@ -48,6 +49,24 @@ export default class BindingWrapper {
this.isReadOnly = false;
this.needsLock = false;
this.events = [];
this.dependencies = new Set(this.binding.value.dependencies);
// special case: if you have e.g. `<input type=checkbox bind:checked=selected.done>`
// and `selected` is an object chosen with a <select>, then when `checked` changes,
// we need to tell the component to update all the values `selected` might be
// pointing to
// TODO should this happen in preprocess?
this.binding.value.dependencies.forEach((prop: string) => {
const indirectDependencies = this.element.renderer.component.indirectDependencies.get(prop);
if (indirectDependencies) {
indirectDependencies.forEach(indirectDependency => {
this.dependencies.add(indirectDependency);
});
}
});
block.addDependencies(this.dependencies);
}
fromDom() {
@ -128,24 +147,11 @@ export default class BindingWrapper {
const { name } = getObject(this.binding.value.node);
const { snippet } = this.binding.value;
// special case: if you have e.g. `<input type=checkbox bind:checked=selected.done>`
// and `selected` is an object chosen with a <select>, then when `checked` changes,
// we need to tell the component to update all the values `selected` might be
// pointing to
// TODO should this happen in preprocess?
const dependencies = new Set(this.binding.value.dependencies);
this.binding.value.dependencies.forEach((prop: string) => {
const indirectDependencies = this.element.renderer.component.indirectDependencies.get(prop);
if (indirectDependencies) {
indirectDependencies.forEach(indirectDependency => {
dependencies.add(indirectDependency);
});
}
});
// view to model
const valueFromDom = this.fromDom();
const handler = getEventHandler(this.binding, this.element.renderer, block, name, snippet, dependencies, valueFromDom);
const handler = getEventHandler(this.binding, this.element.renderer, block, name, snippet, this.dependencies, valueFromDom);
// model to view
let updateDom = this.toDom();

@ -2,6 +2,7 @@ import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import BindingWrapper from './Binding';
import Block from '../../../Block';
export default class InputCheckboxBinding extends BindingWrapper {
events = ['change'];
@ -19,10 +20,11 @@ export default class InputCheckboxBinding extends BindingWrapper {
}
constructor(
block: Block,
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.checked);
super(block, element, binding_lookup.checked);
}
fromDom() {

@ -24,6 +24,6 @@ export default class InputCheckboxGroupBinding extends InputRadioGroupBinding {
toDom() {
const condition = `~${this.binding.value.snippet}.indexOf(${this.element.var}.__value)`;
return `${this.element.var}.checked = ${condition};`
return `${this.element.var}.checked = ${condition};`;
}
}

@ -2,6 +2,7 @@ import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import BindingWrapper from './Binding';
import Block from '../../../Block';
export default class InputNumberBinding extends BindingWrapper {
events = ['input'];
@ -19,10 +20,11 @@ export default class InputNumberBinding extends BindingWrapper {
}
constructor(
block: Block,
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.value);
super(block, element, binding_lookup.value);
this.needsLock = true;
}

@ -25,10 +25,11 @@ export default class InputRadioGroupBinding extends BindingWrapper {
}
constructor(
block: Block,
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.group);
super(block, element, binding_lookup.group);
// TODO handle cases involving computed member expressions
const { parts } = flattenReference(this.binding.value.node);

@ -2,6 +2,7 @@ import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import BindingWrapper from './Binding';
import Block from '../../../Block';
export default class InputTextBinding extends BindingWrapper {
events = ['input'];
@ -21,10 +22,11 @@ export default class InputTextBinding extends BindingWrapper {
}
constructor(
block: Block,
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.value);
super(block, element, binding_lookup.value);
this.needsLock = true;
}

@ -17,10 +17,11 @@ export default class SelectBinding extends BindingWrapper {
}
constructor(
block: Block,
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.value);
super(block, element, binding_lookup.value);
this.events = ['change'];
this.needsLock = true;

@ -170,7 +170,7 @@ export default class ElementWrapper extends Wrapper {
.filter(Binding => {
return Binding.filter(this.node, binding_lookup, type);
})
.map(Binding => new Binding(this, binding_lookup));
.map(Binding => new Binding(block, this, binding_lookup));
// TODO remove this, it's just useful during refactoring
if (has_bindings && !this.bindings.length) {

@ -4,4 +4,4 @@
</label>
{/each}
<p>{selected.map( function ( value ) { return value.name; }).join( ', ' ) }</p>
<p>{selected.map(v => v.name).join(', ')}</p>
Loading…
Cancel
Save