Merge pull request #387 from sveltejs/gh-311

implement bind:group for radio input groups
pull/389/head
Rich Harris 8 years ago committed by GitHub
commit 6907d2657a

@ -16,8 +16,9 @@ export default function createBinding ( generator, node, attribute, current, loc
const handler = current.getUniqueName( `${local.name}ChangeHandler` );
const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue
const type = getStaticAttributeValue( node, 'type' );
const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, current, attribute, keypath ) : null;
const value = getBindingValue( generator, local, node, attribute, isMultipleSelect, bindingGroup );
const value = getBindingValue( generator, local, node, attribute, isMultipleSelect, bindingGroup, type );
const eventName = getBindingEventName( node );
let setter = getSetter({ current, name, context: '__svelte', attribute, dependencies, snippet, value });
@ -26,7 +27,7 @@ export default function createBinding ( generator, node, attribute, current, loc
// <select> special case
if ( node.name === 'select' ) {
if ( !isMultipleSelect ) {
setter = `var selectedOption = ${local.name}.selectedOptions[0] || ${local.name}.options[0];\n` + setter;
setter = `var selectedOption = ${local.name}.selectedOptions[0] || ${local.name}.options[0];\n${setter}`;
}
const value = generator.current.getUniqueName( 'value' );
@ -54,27 +55,28 @@ export default function createBinding ( generator, node, attribute, current, loc
// <input type='checkbox|radio' bind:group='selected'> special case
else if ( attribute.name === 'group' ) {
const type = getStaticAttributeValue( node, 'type' );
if ( type === 'radio' ) {
setter = deindent`
if ( !${local.name}.checked ) return;
${setter}
component._bindingGroups[${bindingGroup}].forEach( function ( input ) {
input.checked = false;
});`;
}
if ( type === 'checkbox' ) {
local.init.addLine(
`component._bindingGroups[${bindingGroup}].push( ${local.name} );`
);
const condition = type === 'checkbox' ?
`~${snippet}.indexOf( ${local.name}.__value )` :
`${local.name}.__value === ${snippet}`;
local.teardown.addBlock(
`component._bindingGroups[${bindingGroup}].splice( component._bindingGroups[${bindingGroup}].indexOf( ${local.name} ), 1 );`
);
local.init.addLine(
`component._bindingGroups[${bindingGroup}].push( ${local.name} );`
);
updateElement = `${local.name}.checked = ~${snippet}.indexOf( ${local.name}.__value );`;
}
else if ( type === 'radio' ) {
throw new Error( 'TODO' );
}
local.teardown.addBlock(
`component._bindingGroups[${bindingGroup}].splice( component._bindingGroups[${bindingGroup}].indexOf( ${local.name} ), 1 );`
);
else {
throw new Error( `Unexpected bind:group` ); // TODO catch this in validation with a better error
}
updateElement = `${local.name}.checked = ${condition};`;
}
// everything else
@ -122,7 +124,7 @@ function getBindingEventName ( node ) {
return 'change';
}
function getBindingValue ( generator, local, node, attribute, isMultipleSelect, bindingGroup ) {
function getBindingValue ( generator, local, node, attribute, isMultipleSelect, bindingGroup, type ) {
// <select multiple bind:value='selected>
if ( isMultipleSelect ) {
return `[].map.call( ${local.name}.selectedOptions, function ( option ) { return option.__value; })`;
@ -135,7 +137,11 @@ function getBindingValue ( generator, local, node, attribute, isMultipleSelect,
// <input type='checkbox' bind:group='foo'>
if ( attribute.name === 'group' ) {
return `${generator.helper( 'getBindingGroupValue' )}( component._bindingGroups[${bindingGroup}] )`;
if ( type === 'checkbox' ) {
return `${generator.helper( 'getBindingGroupValue' )}( component._bindingGroups[${bindingGroup}] )`;
}
return `${local.name}.__value`;
}
// everything else

@ -0,0 +1,78 @@
const values = [
{ name: 'Alpha' },
{ name: 'Beta' },
{ name: 'Gamma' }
];
export default {
data: {
values,
selected: values[1]
},
'skip-ssr': true, // values are rendered as [object Object]
html: `
<label>
<input type="radio"> Alpha
</label>
<label>
<input type="radio"> Beta
</label>
<label>
<input type="radio"> Gamma
</label>
<p>Beta</p>`,
test ( assert, component, target, window ) {
const inputs = target.querySelectorAll( 'input' );
assert.equal( inputs[0].checked, false );
assert.equal( inputs[1].checked, true );
assert.equal( inputs[2].checked, false );
const event = new window.Event( 'change' );
inputs[0].checked = true;
inputs[0].dispatchEvent( event );
assert.htmlEqual( target.innerHTML, `
<label>
<input type="radio"> Alpha
</label>
<label>
<input type="radio"> Beta
</label>
<label>
<input type="radio"> Gamma
</label>
<p>Alpha</p>
` );
component.set({ selected: values[2] });
assert.equal( inputs[0].checked, false );
assert.equal( inputs[1].checked, false );
assert.equal( inputs[2].checked, true );
assert.htmlEqual( target.innerHTML, `
<label>
<input type="radio"> Alpha
</label>
<label>
<input type="radio"> Beta
</label>
<label>
<input type="radio"> Gamma
</label>
<p>Gamma</p>
` );
}
};

@ -0,0 +1,7 @@
{{#each values as value}}
<label>
<input type="radio" value="{{value}}" bind:group='selected' /> {{value.name}}
</label>
{{/each}}
<p>{{selected.name}}</p>
Loading…
Cancel
Save