fix select edge case

pull/769/head
Rich Harris 8 years ago
parent 531354fc39
commit 5070219218

@ -47,10 +47,26 @@ export default function visitAttribute(
if (isDynamic) { if (isDynamic) {
let value; let value;
const allDependencies = new Set();
let shouldCache;
let hasChangeableIndex;
if (attribute.value.length === 1) { if (attribute.value.length === 1) {
// single {{tag}} — may be a non-string // single {{tag}} — may be a non-string
const { snippet } = block.contextualise(attribute.value[0].expression); const { expression } = attribute.value[0];
const { snippet, dependencies, indexes } = block.contextualise(expression);
value = snippet; value = snippet;
dependencies.forEach(d => {
allDependencies.add(d);
});
hasChangeableIndex = Array.from(indexes).some(index => block.changeableIndexes.get(index));
shouldCache = (
expression.type !== 'Identifier' ||
block.contexts.has(expression.name) ||
hasChangeableIndex
);
} else { } else {
// '{{foo}} {{bar}}' — treat as string concatenation // '{{foo}} {{bar}}' — treat as string concatenation
value = value =
@ -60,22 +76,35 @@ export default function visitAttribute(
if (chunk.type === 'Text') { if (chunk.type === 'Text') {
return stringify(chunk.data); return stringify(chunk.data);
} else { } else {
const { snippet } = block.contextualise(chunk.expression); const { snippet, dependencies, indexes } = block.contextualise(chunk.expression);
if (Array.from(indexes).some(index => block.changeableIndexes.get(index))) {
hasChangeableIndex = true;
}
dependencies.forEach(d => {
allDependencies.add(d);
});
return `( ${snippet} )`; return `( ${snippet} )`;
} }
}) })
.join(' + '); .join(' + ');
shouldCache = true;
} }
const last = block.getUniqueName( const isSelectValueAttribute =
name === 'value' && state.parentNodeName === 'select';
const last = (shouldCache || isSelectValueAttribute) && block.getUniqueName(
`${state.parentNode}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value` `${state.parentNode}_${name.replace(/[^a-zA-Z_$]/g, '_')}_value`
); );
block.addVariable(last);
const isSelectValueAttribute = if (shouldCache || isSelectValueAttribute) block.addVariable(last);
name === 'value' && state.parentNodeName === 'select';
let updater; let updater;
const init = shouldCache ? `${last} = ${value}` : value;
if (isSelectValueAttribute) { if (isSelectValueAttribute) {
// annoying special case // annoying special case
@ -104,27 +133,48 @@ export default function visitAttribute(
} }
`; `;
block.builders.hydrate.addLine(deindent` block.builders.hydrate.addBlock(deindent`
${last} = ${value} ${last} = ${value};
${updater} ${updater}
`); `);
block.builders.update.addLine(`${last} = ${value};`);
} else if (propertyName) { } else if (propertyName) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`${state.parentNode}.${propertyName} = ${last} = ${value};` `${state.parentNode}.${propertyName} = ${init};`
); );
updater = `${state.parentNode}.${propertyName} = ${last};`; updater = `${state.parentNode}.${propertyName} = ${shouldCache || isSelectValueAttribute ? last : value};`;
} else { } else {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`${method}( ${state.parentNode}, '${name}', ${last} = ${value} );` `${method}( ${state.parentNode}, '${name}', ${init} );`
); );
updater = `${method}( ${state.parentNode}, '${name}', ${last} );`; updater = `${method}( ${state.parentNode}, '${name}', ${shouldCache || isSelectValueAttribute ? last : value} );`;
} }
block.builders.update.addBlock(deindent` if (allDependencies.size || hasChangeableIndex || isSelectValueAttribute) {
if ( ${last} !== ( ${last} = ${value} ) ) { const dependencies = Array.from(allDependencies);
${updater} const changedCheck = (
} ( block.hasOutroMethod ? `#outroing || ` : '' ) +
`); dependencies.map(dependency => `'${dependency}' in changed`).join(' || ')
);
const updateCachedValue = `${last} !== ( ${last} = ${value} )`;
const condition = shouldCache ?
( dependencies.length ? `( ${changedCheck} ) && ${updateCachedValue}` : updateCachedValue ) :
changedCheck;
// block.builders.update.addConditionalLine(
// condition,
// updater
// );
block.builders.update.addBlock(deindent`
if ( ${condition} ) {
${updater}
}
`);
}
} else { } else {
const value = attribute.value === true const value = attribute.value === true
? 'true' ? 'true'

@ -1,24 +1,38 @@
import counter from './counter.js';
export default { export default {
data: { data: {
x: 1, x: 1,
y: 2 y: 2,
z: 3
}, },
html: ` html: `
<p>1</p> <p>1</p>
<p>2</p> <p class='2'>3</p>
`, `,
test(assert, component) { test(assert, component) {
global.count = 0; counter.y = counter.z = 0;
component.set({ x: 4 });
assert.equal(counter.y, 0);
assert.equal(counter.z, 0);
component.set({ x: 5, y: 6 });
assert.equal(counter.y, 1);
assert.equal(counter.z, 0);
component.set({ x: 3 }); component.set({ x: 6, y: 6 });
assert.equal(global.count, 0); assert.equal(counter.y, 1);
assert.equal(counter.z, 0);
component.set({ x: 4, y: 5 }); component.set({ z: 7 });
assert.equal(global.count, 1); assert.equal(counter.y, 1);
assert.equal(counter.z, 1);
component.set({ x: 5, y: 5 }); component.set({ x: 8, z: 7 });
assert.equal(global.count, 1); assert.equal(counter.y, 1);
assert.equal(counter.z, 1);
} }
}; };

@ -1,11 +1,18 @@
<p>{{x}}</p> <p>{{x}}</p>
<p>{{myHelper(y)}}</p> <p class='{{getClass(y)}}'>{{myHelper(z)}}</p>
<script> <script>
import counter from './counter.js';
export default { export default {
helpers: { helpers: {
getClass(value) {
counter.y += 1;
return value;
},
myHelper(value) { myHelper(value) {
global.count += 1; counter.z += 1;
return value; return value;
} }
} }

Loading…
Cancel
Save