user12302978
user12302978

Reputation:

I need to open and close accordion based on arrow click

I am using Material UI accordion my issue is if I click on the arrow accordion will get open but again I click on the arrow it will not get closed I need to set it when the user clicks on the arrow according will close and open based on the arrow click check code sandbox link for better understanding.

export default function ControlledAccordions() {
  const [expanded, setExpanded] = React.useState(false);

  // const handleChange = (panel) => (event, isExpanded) => {
  //   setExpanded(isExpanded ? panel : false);
  // };
  const handleChange = (pannel) => {
    setExpanded(pannel);
  };
  const panaalData = ["panel1", "panel2", "panel3", "panel4"];
  return (
    <div>
      {panaalData.map((value, i) => {
        return (
          <Accordion expanded={expanded === `panel${i}`}>
            <AccordionSummary
              expandIcon={
                <ExpandMoreIcon
                  onClick={() => {
                    handleChange(`panel${i}`);
                  }}
                  style={{ cursor: "pointer" }}
                />
              }
              aria-controls="panel1d-content"
              id="panel1d-header"
            >
              fdsfdsf
            </AccordionSummary>
            <AccordionDetails>dfdf</AccordionDetails>
          </Accordion>
        );
      })}
    </div>
  );
}

Code SandBox Link

Upvotes: 1

Views: 1007

Answers (5)

Yilmaz
Yilmaz

Reputation: 49293

export default function ControlledAccordions() {
  // initial state, everything is closed,
  const [expandedIndex, setExpandedIndex] = React.useState(-1);

  // this should be handleClic
  const handleChange = (index) => {
    // in useState, current expandedIndex is passed as the argument
    // whatever we return will be set as the expandedIndex
    setExpandedIndex((currentIndex) => {
      // if any box is open, currentIndex will be that index
      // when I click on the open box, it will set the expandedIndex=-1
      if (currentIndex === index) {
        return -1;
      } else {
        // If I reached here, that means I am on a closed box
        // when I click I swithc the expandedIndex to current box's index
        return index;
      }
    });
  };
  const panaalData = ["panel1", "panel2", "panel3", "panel4"];
  return (
    <div>
      {panaalData.map((value, i) => {
        // when handleChange runs on AccordionSummary expandedIndex===i
        // that means when i click on the current box, it will be open
        const isExpanded = expandedIndex === i;
        return (
          <Accordion expanded={isExpanded}>
            <AccordionSummary
              onClick={() => handleChange(i)}
              expandIcon={
                // I dont know @mui/material too much. 
                // main question is "I need to open and close accordion based on arrow click"
                <ExpandMoreIcon
                  onClick={() => handleChange(i)}
                  style={{ cursor: "pointer" }}
                />
              }
              aria-controls="panel1d-content"
              id="panel1d-header"
            >
              {value}
            </AccordionSummary>
            <AccordionDetails
              style={{ backgroundColor: "green" }}
            >{`box index ${i} is open`}</AccordionDetails>
          </Accordion>
        );
      })}
    </div>
  );
}

proof of work:

enter image description here

Upvotes: 0

CraZyDroiD
CraZyDroiD

Reputation: 7105

const handleChange = (pannel) => {
    setExpanded(!pannel);
  };

Upvotes: 0

Amila Senadheera
Amila Senadheera

Reputation: 13245

Create another component called MyAccordian and keep toggling accordion logic in that component. That way you don't need to handle toggling for each and every component separately.

export default function ControlledAccordions() {
  const panaalData = ["panel1", "panel2", "panel3", "panel4"];
  return (
    <div>
      {panaalData.map((value, i) => {
        return <MyAccordian value={value} />;
      })}
    </div>
  );
}

const MyAccordian = ({ value }) => {
  const [expanded, setExpanded] = React.useState(false);

  return (
    <Accordion expanded={expanded}>
      <AccordionSummary
        expandIcon={
          <ExpandMoreIcon
            onClick={() => {
              setExpanded((prev) => !prev);
            }}
            style={{ cursor: "pointer" }}
          />
        }
        aria-controls="panel1d-content"
        id="panel1d-header"
      >
        {value}
      </AccordionSummary>
      <AccordionDetails>{value}</AccordionDetails>
    </Accordion>
  );
};

Working Demo

Edit beautiful-browser-5jys6l

Upvotes: 0

dsalex1
dsalex1

Reputation: 464

when you click the already expanded panel, it just sets it to be expanded again.

you need to check whether the clicked panel is already expanded and if so collapse it instead of expanding it:

  const handleChange = (pannel) => {
    if (expanded === pannel) setExpanded(false);
    else setExpanded(pannel);
  }; 

Upvotes: 1

Asad Gulzar
Asad Gulzar

Reputation: 672

you need to reset panel in that case. You can do that in change handler.

const handleChange = (pannel) => {
   setExpanded(expended === pannel ? '' : pannel);
};

Upvotes: 1

Related Questions