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);
}}