Search code examples
javascriptreactjsfont-awesome

React Fontawesome Icon on Button not Allowing Id to be Accessed


I am using react fontawesome in my project. Under the render function of my component I have the following which maps a school onto the page and then I want a button with an edit icon to perform an action. My code for the button looks as below:

      { this.state.myschools.map( (school) => (
          <Row key={school.id}>
            <Col><p>{school.name}</p></Col>
            { school.deaths.length > 0 ? <Col md="2"><button id={school.id} className="likelink" onClick={this.goToSchoolDeathList}>View Deaths</button></Col> : <Col md="2"></Col> }
            <Col><button id={school.id} onClick={this.editSchool}><FontAwesomeIcon icon={faEdit} /></button></Col>
          </Row>
        ))}

The editSchool function is as:

  editSchool(e) {
      console.log("School Id");
      console.log(e.target.id);
  }

If I click on the empty space around the font awesome icon then the id is logged to the console. If I only click on the area where the icon exits then the id is not logged. I want the user to be able to click on any part of the button including the fa icon and to capture the school id.

I have tried adding the onClick event and the id attribute to the "FontAwesomeIcon" component, but that still doesn't work.

Can anyone help?


Solution

  • Well, this is one of the common pitfall you learn during your time with React. Rest assure, we have all fallen into this pit.

    There are few AHA moments here.

    1st Aha: React doesn't have a usual way to let you get element attribute in an event (an e in your example).

    That being said, you can still access to the button element by e.target and use JavaScript to get attribute.

    Solution #1 JavaScript getAttribute

    editSchool(e) {
      console.log("School Id");
      console.log(e.target.getAttribute('id'));
    }
    

    e.target will be the HTML Element that you click, and we can use JavaScript way to get attribute. (Please Note that, Javascript way is not React way)

    But there are another way and you'll see this way more often.

    Solution #2 You can define a function directly in a render

    <button id={school.id} onClick={e => this.editSchool(school.id)}>
    

    Please be careful about this another pitfall,

    2nd Aha: Bind onClick to function, not result of a function.

    Don't do this

    <button id={school.id} onClick={this.editSchool(scholl.id)}> // This is incorrect
    

    The thing is onClick prop expect a function to call when someone click.

    The first one we define a function e => this.editSchool(school.id) and bind onClick with the newly defined function.

    While the second, we just bind onClick to a "result" of function this.editSchool(school.id), which is not a function.