Home > other >  How to differentiates buttons and behaviour in a function
How to differentiates buttons and behaviour in a function

Time:07-02

I have a list of items; Each item has a "Details" button beside it.

When the "Details" button it is pressed, I would like to show under the list the details of that element.

So far so good. I managed to do it. Even if it doesn't seem the best way. Now the problem is:

When I press, for the first time, a button, it shows the details of that item. But when I press again, regardless of the button, it close it. This is because I don't understand how to differentiate them. So for closing the "Details" I can just hit any button, and I don't want it.

My desired behavior would be (pseudo code):

if details_not_showing:
   show_details(id==button_pressed)
else:
   if details_showing == details_from_button_pressed
      close_details()
   else
      show_details(id==button_pressed)

Hoping this make some sense, I leave you with my terrible code under this.

Imports

import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";

Function

function MonthArticles() {
  const { user_id, year, month } = useParams();
  const url =
    "http://127.0.0.1:8000/api/"   user_id   "/posts/"   year   "/"   month;
  const url_retrieve_author = "http://127.0.0.1:8000/api/retrieve-author";

  const formdata = new FormData();
  formdata.append("id", user_id);
  const requestOptions = {
    method: "POST",
    body: formdata,
  };

  const [article, setArticle] = useState([]);
  useEffect(() => {
    fetch(url, {
      method: "GET",
    })
      .then((res) => res.json())
      .then((data) => {
        setArticle(data);
      });
  }, []);

  const [author, setAuthor] = useState([]);
  useEffect(() => {
    fetch(url_retrieve_author, requestOptions)
      .then((res) => res.json())
      .then((data) => {
        setAuthor(data);
      });
  }, []);

  const [details, setDetails] = useState(false);
  const [articleId, setArticleId] = useState();

  return (
    <div>
      <h2>
        Articles writte in {year}, {month} - By{" "}
        {author.map((author) => (
          <div key={author.id}>{author.last_name}</div>
        ))}
      </h2>
      <h4>List of articles below:</h4>
      <ul>
        {article.map((article) => (
          <div key={article.id}>
            <li key={article.id}>
              {article.title}{" "}
              <button
                id={article.id}
                type='button'
                onClick={() => [
                  setDetails((currentDetails) => !currentDetails),
                  setArticleId(article.id),
                ]}
              >
                Details
              </button>
            </li>
          </div>
        ))}
      </ul>

      {details ? (
        <div>
          <h3>Showing details</h3>
          {article
            .filter((a) => a.id === articleId)
            .map((filteredArticle) => (
              <div>
                <h4>Post created in: {filteredArticle.date_created}</h4>
                <p>{filteredArticle.text}</p>
              </div>
            ))}
        </div>
      ) : null}
    </div>
  );
}

Thanks in advance

CodePudding user response:

Just check on click if the id doesn't change then return null to hide the details, if not set the new article id to show the details.

function MonthArticles() {
  const { user_id, year, month } = useParams();
  const url =
    "http://127.0.0.1:8000/api/"   user_id   "/posts/"   year   "/"   month;
  const url_retrieve_author = "http://127.0.0.1:8000/api/retrieve-author";

  const formdata = new FormData();
  formdata.append("id", user_id);
  const requestOptions = {
    method: "POST",
    body: formdata,
  };

  const [article, setArticle] = useState([]);
  useEffect(() => {
    fetch(url, {
      method: "GET",
    })
      .then((res) => res.json())
      .then((data) => {
        setArticle(data);
      });
  }, []);

  const [author, setAuthor] = useState([]);
  useEffect(() => {
    fetch(url_retrieve_author, requestOptions)
      .then((res) => res.json())
      .then((data) => {
        setAuthor(data);
      });
  }, []);

  const [details, setDetails] = useState(false);
  const [articleId, setArticleId] = useState();

  return (
    <div>
      <h2>
        Articles writte in {year}, {month} - By{" "}
        {author.map((author) => (
          <div key={author.id}>{author.last_name}</div>
        ))}
      </h2>
      <h4>List of articles below:</h4>
      <ul>
        {article.map((article) => (
          <div key={article.id}>
            <li key={article.id}>
              {article.title}{" "}
              <button
                id={article.id}
                type='button'
                onClick={() => [
                  setDetails((currentDetails) => !currentDetails),
                  setArticleId(prev => {
                    if (prev === articleId) return null
                    return article.id
                  }),
                ]}
              >
                Details
              </button>
            </li>
          </div>
        ))}
      </ul>

      {details ? (
        <div>
          <h3>Showing details</h3>
          {article
            .filter((a) => a.id === articleId)
            .map((filteredArticle) => (
              <div>
                <h4>Post created in: {filteredArticle.date_created}</h4>
                <p>{filteredArticle.text}</p>
              </div>
            ))}
        </div>
      ) : null}
    </div>
  );
}

CodePudding user response:

Currently, in your buttons onClick functions you do this:

onClick={() => [
      setDetails((currentDetails) => !currentDetails),
      setArticleId(article.id),
]}

The first line toggles whether or not the details secions is visible. All buttons currently toggle the details visibility. What you want is to only do this when it is the button corresponding to the currently displayed details.

onClick={() => {
      //If no details are visible, show them
      if(!details) setDetails(true);   
      //If details are visible, and this is the corresponding button, hide them
      else if(article.id == articleId) setDetails(false); 
      setArticleId(article.id);
}}
  • Related