Skip to content

Instantly share code, notes, and snippets.

@derek
Created January 11, 2012 22:30
Show Gist options
  • Save derek/1597168 to your computer and use it in GitHub Desktop.
Save derek/1597168 to your computer and use it in GitHub Desktop.
Y.ButtonGroup

Y.ButtonGroup

Problem

I have multiple Y.Button instances that are logically associated and need to be managed as a group.

For example, you may need a radio group, so when one button becomes selected, the others are unselected. Or a checkbox group, which allows you to select multiple buttons and at some point you need to obtain the values of all selected buttons.

Note: A push group is really just a checkbox group, but with Y.Button instances whose types are push as opposed to toggle.

Methods

  • addButton - Adds a button to the group
  • getButtons - Returns an array of Y.Button instances assigned to the group
  • getSelectedButtons - Returns an array of Y.Button instances that are currently selected
  • getSelectedValues - Returns an array of the values of select buttons (sugar)

Attributes

  • type ('checkbox' [default], or 'radio')

Events

  • selectionChange - Fires after the selected state on a grouped button changes.

Dependencies

  • button-base (requires: base, classnamemanager, node)

Example

// Instantiation
group = new Y.ButtonGroup({type: 'radio'});
buttonA = new Y.Button({srcNode: "#foo"});
buttonB = new Y.Button({srcNode: "#bar"});

// Interaction
group.addButton(ButtonA);
group.addButton(ButtonB);

buttonA.select();
selected = group.getSelectedButtons(); // Returns buttonA

buttonB.select();
selected = group.getSelectedButtons(); // Returns buttonB

Considerations

  • Add support for a buttons attribute in the Y.ButtonGroup config object to add all buttons on instantiation. Update: see comment #4
  • Add support for a srcNodes selector attribute in the Y.ButtonGroup config object to create Y.Button instances for each node and add to the group. Update: see comment #4
  • Add support for a click event (exact name TBD) which fires when any button in the group is clicked. This would be most applicable to push button groups.
@derek
Copy link
Author

derek commented Jan 12, 2012

To investigate @hatched's request, here's some implementation examples for supporting srcNodes and buttons config attributes. All 3 are pretty much identical in terms of output/result, just different approaches.


A: Instantiate with srcNodes instead of using addButton();

<div id='container'>
    <button class='myButtons' value='foo'>Foo</button>
    <button class='myButtons' value='bar'>Bar</button>
</div>
var group = new Y.ButtonGroup({
    srcNodes: '.myButtons' // or Y.all('.myButtons')
});

var myButtons = group.getButtons();

B: Instantiate with buttons instead of using addButton();

<div id='container'>
    <button id='foo' value='foo'>Foo</button>
    <button id='bar' value='bar'>Bar</button>
</div>
var buttonA = new Y.Button({srcNode: '#foo'});
var buttonB = new Y.Button({srcNode: '#bar'});
var myButtons = [buttonA, buttonB];

var group = new Y.ButtonGroup({
    buttons: myButtons
});

C: Instantiate with buttons instead of using addButton();, but with items not yet in the DOM, then later add them

<div id='container'></div>
var buttonA = new Y.Button({label: 'foo'});
var buttonB = new Y.Button({label: 'bar'});

var group = new Y.ButtonGroup({
    buttons: [buttonA, buttonB]
});

var myButtons = group.getButtons();

Y.Array.each(myButtons, function(button){
    var node = button.getNode();
    // Because Y.Button instantiation doesn't support a 'value' attribute. Will consider.
    node.set('value', button.get('label'));
    Y.one('#container').append(node);
});

@derek
Copy link
Author

derek commented Jan 12, 2012

@rgrove: to answer your question, Tripp & I couldn't think of any other 80% use-case for a group of buttons outside of a menu bar or tool bar. For those, it will be either push, radio, or toggle.

"or is button creation and event management left entirely up to Y.Button and the implementor?"

For the most part, yes. However, ButtonGroup will fire selectionChange (which I forgot to add to the Gist before, added) and an implementer can subscribe to that instead of listening on all buttons.

@hatched
Copy link

hatched commented Jan 12, 2012

Methods A & B look great, my 80% usecase method would be A.

Was there a reason as to why there is no value attribute? If Y.Button doesn't have the ability to create full markup with the instantiation I woudln't include it at all. There will be a lot of essentially useless code weight there as the dev has to edit the markup after the fact anyways and would be better off creating the nodes outside of Y.Button with something like Y.Node.create() and using methods A or B.

@derek
Copy link
Author

derek commented Jan 12, 2012

Actually, Y.Button creating nodes on the fly was a late addition. It would be preferable for the developer to use Y.Node.create() so then they have full control over the button. But feedback was that it seemed logical for Y.Button to also create buttons, which does make sense, so I added that in. If srcNode is empty at instantiation, it assigns that attritbute as Y.Node.create('<button></button>');.

Instead of Y.Button supporting value directly, it abstracts it out into a label attribute (which I think is what YUI 2 did). But now that I review the code that renders that attribute, I see an issue:

_renderLabel: function (value) {
    var node = this.getNode();
    node.set(node.test('input') ? 'value' : 'text', value);
},

It works fine for <div>, <a>, etc..., and since <input> only has a value attribute (no innerHTML) it will work fine for that as well. But what about a <button> node, which has both value and innerHTML/text? A single label attribute won't work, so I'll have to fix that.

It's not quite as simple as just throwing in a value attribute, because what happens here?

var button = new Y.Button({
    srcNode: Y.Node.create('<div></div>'),
    label: 'I am a Button!',
    value: 'No you are not, you just look like one'
})

<button> and <input> both have a value attribute, but a <div>, <a>, etc... do not. So does Y.Button just ignore the value property? Does it assign it as a custom attribute? It's probably one of those "You should know better that to do this" things, but you never know, and I haven't had a chance to fully think through it yet.

So, I'll work to resolve this issue before 3.5.0pr2.

Good question. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment