bind to destructured properties

pull/1385/head
Rich Harris 7 years ago
parent 9607593705
commit 70034ea997

@ -9,8 +9,7 @@ export interface BlockOptions {
compiler?: Compiler;
comment?: string;
key?: string;
indexNames?: Map<string, string>;
listNames?: Map<string, string>;
bindings?: Map<string, string>;
dependencies?: Set<string>;
}
@ -23,8 +22,8 @@ export default class Block {
first: string;
dependencies: Set<string>;
indexNames: Map<string, string>;
listNames: Map<string, string>;
bindings: Map<string, string>;
builders: {
init: CodeBuilder;
@ -62,8 +61,7 @@ export default class Block {
this.dependencies = new Set();
this.indexNames = options.indexNames;
this.listNames = options.listNames;
this.bindings = options.bindings;
this.builders = {
init: new CodeBuilder(),

@ -195,14 +195,13 @@ function getEventHandler(
? getTailSnippet(binding.value.node)
: '';
const list = `ctx.${block.listNames.get(name)}`;
const index = `ctx.${block.indexNames.get(name)}`;
const head = block.bindings.get(name);
return {
usesContext: true,
usesState: true,
usesStore: storeDependencies.length > 0,
mutation: `${list}[${index}]${tail} = ${value};`,
mutation: `${head}${tail} = ${value};`,
props: dependencies.map(prop => `${prop}: ctx.${prop}`),
storeProps: storeDependencies.map(prop => `${prop}: $.${prop}`)
};

@ -239,12 +239,11 @@ export default class Component extends Node {
const computed = isComputed(binding.value.node);
const tail = binding.value.node.type === 'MemberExpression' ? getTailSnippet(binding.value.node) : '';
const list = block.listNames.get(key);
const index = block.indexNames.get(key);
const head = block.bindings.get(key);
const lhs = binding.value.node.type === 'MemberExpression'
? binding.value.snippet
: `ctx.${list}[ctx.${index}]${tail} = childState.${binding.name}`;
: `${head}${tail} = childState.${binding.name}`;
setFromChild = deindent`
${lhs} = childState.${binding.name};

@ -76,15 +76,16 @@ export default class EachBlock extends Node {
name: this.compiler.getUniqueName('create_each_block'),
key: this.key,
indexNames: new Map(block.indexNames),
listNames: new Map(block.listNames)
bindings: new Map(block.bindings)
});
const listName = this.compiler.getUniqueName('each_value');
this.each_block_value = this.compiler.getUniqueName('each_value');
const indexName = this.index || this.compiler.getUniqueName(`${this.context}_index`);
this.block.indexNames.set(this.context, indexName);
this.block.listNames.set(this.context, listName);
this.contexts.forEach(prop => {
this.block.bindings.set(prop.key.name, `ctx.${this.each_block_value}[ctx.${indexName}]${prop.tail}`);
});
if (this.index) {
this.block.getUniqueName(this.index); // this prevents name collisions (#1254)
@ -94,7 +95,7 @@ export default class EachBlock extends Node {
// TODO only add these if necessary
this.contextProps.push(
`${listName}: list`,
`${this.each_block_value}: list`,
`${indexName}: i`
);
@ -131,7 +132,6 @@ export default class EachBlock extends Node {
const each = this.var;
const create_each_block = this.block.name;
const each_block_value = this.block.listNames.get(this.context);
const iterations = this.iterations;
const needsAnchor = this.next ? !this.next.isDomNode() : !parentNode || !this.parent.isDomNode();
@ -150,7 +150,6 @@ export default class EachBlock extends Node {
const vars = {
each,
create_each_block,
each_block_value,
length,
iterations,
anchor,
@ -159,7 +158,7 @@ export default class EachBlock extends Node {
const { snippet } = this.expression;
block.builders.init.addLine(`var ${each_block_value} = ${snippet};`);
block.builders.init.addLine(`var ${this.each_block_value} = ${snippet};`);
this.compiler.target.blocks.push(deindent`
function ${this.get_each_context}(ctx, list, i) {
@ -191,7 +190,7 @@ export default class EachBlock extends Node {
// TODO neaten this up... will end up with an empty line in the block
block.builders.init.addBlock(deindent`
if (!${each_block_value}.${length}) {
if (!${this.each_block_value}.${length}) {
${each_block_else} = ${this.else.block.name}(#component, ctx);
${each_block_else}.c();
}
@ -207,9 +206,9 @@ export default class EachBlock extends Node {
if (this.else.block.hasUpdateMethod) {
block.builders.update.addBlock(deindent`
if (!${each_block_value}.${length} && ${each_block_else}) {
if (!${this.each_block_value}.${length} && ${each_block_else}) {
${each_block_else}.p(changed, ctx);
} else if (!${each_block_value}.${length}) {
} else if (!${this.each_block_value}.${length}) {
${each_block_else} = ${this.else.block.name}(#component, ctx);
${each_block_else}.c();
${each_block_else}.${mountOrIntro}(${initialMountNode}, ${anchor});
@ -221,7 +220,7 @@ export default class EachBlock extends Node {
`);
} else {
block.builders.update.addBlock(deindent`
if (${each_block_value}.${length}) {
if (${this.each_block_value}.${length}) {
if (${each_block_else}) {
${each_block_else}.u();
${each_block_else}.d();
@ -263,7 +262,6 @@ export default class EachBlock extends Node {
{
each,
create_each_block,
each_block_value,
length,
anchor,
mountOrIntro,
@ -291,8 +289,8 @@ export default class EachBlock extends Node {
block.builders.init.addBlock(deindent`
const ${get_key} = ctx => ${this.key.snippet};
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
let child_ctx = ${this.get_each_context}(ctx, ${each_block_value}, #i);
for (var #i = 0; #i < ${this.each_block_value}.${length}; #i += 1) {
let child_ctx = ${this.get_each_context}(ctx, ${this.each_block_value}, #i);
let key = ${get_key}(child_ctx);
${blocks}[#i] = ${lookup}[key] = ${create_each_block}(#component, key, child_ctx);
}
@ -319,9 +317,9 @@ export default class EachBlock extends Node {
const dynamic = this.block.hasUpdateMethod;
block.builders.update.addBlock(deindent`
var ${each_block_value} = ${snippet};
var ${this.each_block_value} = ${snippet};
${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${each_block_value}, ${lookup}, ${updateMountNode}, ${String(this.block.hasOutroMethod)}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.get_each_context});
${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.each_block_value}, ${lookup}, ${updateMountNode}, ${String(this.block.hasOutroMethod)}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.get_each_context});
`);
if (!parentNode) {
@ -342,7 +340,6 @@ export default class EachBlock extends Node {
snippet: string,
{
create_each_block,
each_block_value,
length,
iterations,
anchor,
@ -352,8 +349,8 @@ export default class EachBlock extends Node {
block.builders.init.addBlock(deindent`
var ${iterations} = [];
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
${iterations}[#i] = ${create_each_block}(#component, ${this.get_each_context}(ctx, ${each_block_value}, #i));
for (var #i = 0; #i < ${this.each_block_value}.${length}; #i += 1) {
${iterations}[#i] = ${create_each_block}(#component, ${this.get_each_context}(ctx, ${this.each_block_value}, #i));
}
`);
@ -441,15 +438,15 @@ export default class EachBlock extends Node {
${iterations}[#i].u();
${iterations}[#i].d();
}
${iterations}.length = ${each_block_value}.${length};
${iterations}.length = ${this.each_block_value}.${length};
`;
block.builders.update.addBlock(deindent`
if (${condition}) {
${each_block_value} = ${snippet};
${this.each_block_value} = ${snippet};
for (var #i = ${start}; #i < ${each_block_value}.${length}; #i += 1) {
const child_ctx = ${this.get_each_context}(ctx, ${each_block_value}, #i);
for (var #i = ${start}; #i < ${this.each_block_value}.${length}; #i += 1) {
const child_ctx = ${this.get_each_context}(ctx, ${this.each_block_value}, #i);
${forLoopBody}
}

@ -23,8 +23,7 @@ export default class Fragment extends Node {
name: '@create_main_fragment',
key: null,
indexNames: new Map(),
listNames: new Map(),
bindings: new Map(),
dependencies: new Set(),
});

@ -77,7 +77,7 @@ export default function readContext(parser: Parser) {
parser.allowWhitespace();
const value = parser.eat(':')
? readContext(parser)
? (parser.allowWhitespace(), readContext(parser))
: key;
const property: Property = {

@ -0,0 +1,39 @@
export default {
data: {
people: [{ name: { first: 'Doctor', last: 'Who' } }],
},
html: `
<input>
<input>
<p>Doctor Who</p>
`,
test(assert, component, target, window) {
const inputs = target.querySelectorAll('input');
inputs[1].value = 'Oz';
inputs[1].dispatchEvent(new window.Event('input'));
const { people } = component.get();
assert.deepEqual(people, [
{ name: { first: 'Doctor', last: 'Oz' } }
]);
assert.htmlEqual(target.innerHTML, `
<input>
<input>
<p>Doctor Oz</p>
`);
people[0].name.first = 'Frank';
component.set({ people });
assert.htmlEqual(target.innerHTML, `
<input>
<input>
<p>Frank Oz</p>
`);
},
};

@ -0,0 +1,5 @@
{#each people as { name: { first: f, last: l } } }
<input bind:value=f>
<input bind:value=l>
<p>{f} {l}</p>
{/each}
Loading…
Cancel
Save