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 handler = current.getUniqueName( `${local.name}ChangeHandler` );
const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue 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 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 ); const eventName = getBindingEventName( node );
let setter = getSetter({ current, name, context: '__svelte', attribute, dependencies, snippet, value }); 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 // <select> special case
if ( node.name === 'select' ) { if ( node.name === 'select' ) {
if ( !isMultipleSelect ) { 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' ); 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 // <input type='checkbox|radio' bind:group='selected'> special case
else if ( attribute.name === 'group' ) { 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' ) { const condition = type === 'checkbox' ?
local.init.addLine( `~${snippet}.indexOf( ${local.name}.__value )` :
`component._bindingGroups[${bindingGroup}].push( ${local.name} );` `${local.name}.__value === ${snippet}`;
);
local.teardown.addBlock( local.init.addLine(
`component._bindingGroups[${bindingGroup}].splice( component._bindingGroups[${bindingGroup}].indexOf( ${local.name} ), 1 );` `component._bindingGroups[${bindingGroup}].push( ${local.name} );`
); );
updateElement = `${local.name}.checked = ~${snippet}.indexOf( ${local.name}.__value );`; local.teardown.addBlock(
} `component._bindingGroups[${bindingGroup}].splice( component._bindingGroups[${bindingGroup}].indexOf( ${local.name} ), 1 );`
);
else if ( type === 'radio' ) {
throw new Error( 'TODO' );
}
else { updateElement = `${local.name}.checked = ${condition};`;
throw new Error( `Unexpected bind:group` ); // TODO catch this in validation with a better error
}
} }
// everything else // everything else
@ -122,7 +124,7 @@ function getBindingEventName ( node ) {
return 'change'; return 'change';
} }
function getBindingValue ( generator, local, node, attribute, isMultipleSelect, bindingGroup ) { function getBindingValue ( generator, local, node, attribute, isMultipleSelect, bindingGroup, type ) {
// <select multiple bind:value='selected> // <select multiple bind:value='selected>
if ( isMultipleSelect ) { if ( isMultipleSelect ) {
return `[].map.call( ${local.name}.selectedOptions, function ( option ) { return option.__value; })`; 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'> // <input type='checkbox' bind:group='foo'>
if ( attribute.name === 'group' ) { 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 // 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