2

How can I get the value of the eventKey attribute and pass it to my function in the following line?

<Accordion.Toggle 
   as={Card.Header} 
   eventKey="2" 
   data-foo="zzz" 
   onClick={(e) => CardClick(e.currentTarget.getAttribute('eventKey') ?? "unknown")}> // unknown.  Desired value: 2

The following is addressed in this question. In my case however the attribute I need to get is not prefixed with "data-".

Works:

<Accordion.Toggle 
   as={Card.Header} 
   eventKey="2" 
   data-foo="zzz" 
   onClick={(e) => CardClick(e.currentTarget.getAttribute('data-foo') ?? "unknown")}> // zzz 

Not works:

<Accordion.Toggle 
   as={Card.Header} 
   eventKey="2" 
   data-foo="zzz" 
   onClick={(e) => CardClick(e.currentTarget.getAttribute('data-eventKey') ?? "unknown")}> // unknown

Complete component:

<Card>
    <Accordion.Toggle as={Card.Header} eventKey="0" className="faq-header" onClick={(e) => CardClick(e.currentTarget.getAttribute('eventKey') ?? "unknown")}>
        <span className="rh5">Some text</span>
    </Accordion.Toggle>
    <Accordion.Collapse eventKey="0">
        <Card.Body>
            <span className="rh6">
                Some text
            </span>
        </Card.Body>
    </Accordion.Collapse>
</Card>
  • 1
    If the attribute exists in the HTML, just change `getAttribute('data-eventKey')` to `getAttribute('eventKey')`? – CertainPerformance Nov 05 '20 at 00:34
  • I tried what you suggested - please see last line in the question. –  Nov 05 '20 at 00:37
  • 1
    If it doesn't exist in the HTML, but rather is only known as a prop for the Accordion, you might have to write out the `"2"` twice, though that seems ugly. Better would be to change the component to render the attribute in the HTML too. – CertainPerformance Nov 05 '20 at 00:40
  • It may be because of your simplified example, but if the `eventKey` is hardcoded (as it appears to be) then why not just hardcode the same value out to `CardClick`? – Drew Reese Nov 05 '20 at 00:55
  • If I don't have to I would rather not. I want to understand the principal, and also I have a ton of these things to maintain and it's just ugly to do it that way. –  Nov 05 '20 at 00:59
  • @Sam Can you share the complete code for your component? – Benjamin Nov 05 '20 at 00:59
  • 1
    Yes, I think we need a bit more context because IMO you're already assigning the `eventKey` and anonymous `onClick` handler props manually so I don't quite understand why here is where you've drawn the line. My point is that at the moment when you are passing `eventKey` a value is the same time you are assigning an `onClick` callback to receive that value, so just pass to the callback the value you want it to have when invoked. This completely removes/cuts out a chunk of unnecessary logic and data wrangling. – Drew Reese Nov 05 '20 at 01:11
  • I think it's fair to not want to hard code something twice. This will not be the greatest length I've gone to too avoid doing it. Also I just want to know how to do it. Kind of like the mountain.... because it's there... –  Nov 05 '20 at 01:28
  • I guess? I think you are still missing the point that you don't need to *actually* pass any data to the element when you can instead just enclose it in the attached callback. Coded once. – Drew Reese Nov 05 '20 at 03:27

1 Answers1

2

As explained by @DrewReese in the comments, it is impossible to get the eventKey from the DOM element (e.target) because it is never passed down to the DOM.

We should get it from the props instead. We do need to use eventKey in three places: as the eventKey prop in both the Toggle and the Collapse and in our onClick. But when it becomes abstracted out as a component prop, we only need to declare the specific event key, ie. eventKey="2", once.

import React from "react";
import { Accordion, Card } from "react-bootstrap";

interface RenderCardProps {
  eventKey: string;
  CardClick: (key: string) => void;
  /** add whatever else you need */
}

const RenderCard = ({ eventKey, CardClick }: RenderCardProps) => {
  return (
    <Card>
      <Accordion.Toggle
        as={Card.Header}
        eventKey={eventKey}
        className="faq-header"
        onClick={() => CardClick(eventKey)}
      >
        <span className="rh5">Some text</span>
      </Accordion.Toggle>
      <Accordion.Collapse eventKey={eventKey}>
        <Card.Body>
          <span className="rh6">Some text</span>
        </Card.Body>
      </Accordion.Collapse>
    </Card>
  );
};

export default () => <RenderCard CardClick={console.log} eventKey="2" />;

You probably want to make ToggleContents and CardContents into props too in order to use this as an actual component.

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102