fadedbee
fadedbee

Reputation: 44715

ReactJS distinguishing clicks from multiple components.

I have a web interface with two buttons:

<Panel header="Green Square">
  <ButtonToolbar>
    <Button bsStyle="info" onClick={this.handleGreenSquareOn}><Glyphicon glyph="ok-circle"/> On</Button>
    <Button bsStyle="info" onClick={this.handleGreenSquareOff}><Glyphicon glyph="remove-circle"/> Off</Button>
  </ButtonToolbar>
</Panel>

and some handling code:

handleGreenSquareOn: function() { return this.handleGreenSquare(true); },
handleGreenSquareOff: function() { return this.handleGreenSquare(false); },
handleGreenSuqare: function(value) {
  // do stuff
},

What's the best way to eliminate the handleGreenSquareOn and handleGreenSquareOff functions?

Is there a way of setting an argument for an onClick callback in the JSX code?

Upvotes: 0

Views: 1232

Answers (3)

Retozi
Retozi

Reputation: 7871

The callbacks on events will provide the data-reactid as a second variable

So if you alter your function like so:

handleGreenSuqare: function(value, reactId) {
  // do stuff with reactId
},

you can parse the reactId which are the component keys concatenated by dots.

If you give your button a key attribute like so:

<Panel header="Green Square">
  <ButtonToolbar>
    <Button key="on" bsStyle="info" onClick={this.handleGreenSquareOn}><Glyphicon glyph="ok-circle"/> On</Button>
    <Button key="off" bsStyle="info" onClick={this.handleGreenSquareOff}><Glyphicon glyph="remove-circle"/> Off</Button>
  </ButtonToolbar>
</Panel>

your reactId variable will somewhat look like this for the off button:

.0.0.1.0.1.$off

inlining the function might be more more expressive, depending on what you are trying to do.

<Panel header="Green Square">
  <ButtonToolbar>
    <Button bsStyle="info" onClick={function() {return this.handleGreenSquare(true);}}><Glyphicon glyph="ok-circle"/> On</Button>
    <Button bsStyle="info" onClick={function() {return this.handleGreenSquare(false);}}><Glyphicon glyph="remove-circle"/> Off</Button>
  </ButtonToolbar>
</Panel>

If you use the es6 harmony features of the jsx compiler, this looks nice and expressive:

<Panel header="Green Square">
  <ButtonToolbar>
    <Button key="on" bsStyle="info" onClick={() => this.handleGreenSquare(true)}><Glyphicon glyph="ok-circle"/> On</Button>
    <Button key="off" bsStyle="info" onClick={() => this.handleGreenSquare(false)}><Glyphicon glyph="remove-circle"/> Off</Button>
  </ButtonToolbar>
</Panel>

Upvotes: 1

David Hellsing
David Hellsing

Reputation: 108500

Modifying the handler’s arguments will also remove the event object (unless you pass it manually). I would keep the handlers intact for consistency, but that’s a design choice.

Another options is to add a data attribute and check it inside the handler:

handleGreenSquare: function(e) {
  var value = e.currentTarget.getAttribute('data-value') == 'on';
}

[...]

<Button data-value="on" key="on" bsStyle="info" onClick={this.handleGreenSquare}><Glyphicon glyph="ok-circle"/> On</Button>
<Button data-value="off" key="off" bsStyle="info" onClick={this.handleGreenSquare}><Glyphicon glyph="remove-circle"/> Off</Button>

Upvotes: 3

nilgun
nilgun

Reputation: 10629

You can just pass an argument to handleGreenSquare like this: onClick={this.handleGreenSquare.bind(this, true)}

Here is a jsfiddle to play with: http://jsfiddle.net/nilgundag/wsdr48ro/

/** @jsx React.DOM */

var Hello = React.createClass({
        handleGreenSquare: function(value) {
          console.log(value);
        },
    render: function() {
        return <ReactBootstrap.Navbar brand="Whoops">
               <ReactBootstrap.Panel header="Green Square">
                     <ReactBootstrap.ButtonToolbar>
            <ReactBootstrap.Button bsStyle="info" onClick={this.handleGreenSquare.bind(this, true)}><ReactBootstrap.Glyphicon glyph="ok-circle"/> On</ReactBootstrap.Button>
            <ReactBootstrap.Button bsStyle="info" onClick={this.handleGreenSquare.bind(this, false)}><ReactBootstrap.Glyphicon glyph="remove-circle"/> Off</ReactBootstrap.Button>
          </ReactBootstrap.ButtonToolbar>

            </ReactBootstrap.Panel>
        </ReactBootstrap.Navbar>;
    }
});

React.renderComponent(<Hello />, document.body);

Upvotes: 5

Related Questions