Expand and Collapse Button for Customizing Table Height Individually

I trust everything is going smoothly. A challenge I'm facing involves implementing a button to expand a specific row within a table. Currently, clicking the "show more/show less" button extends all rows when the goal is to do it for each individual table caption row. Additionally, I want to display the button only if the caption length exceeds 250 characters. Below is the code snippet for better visualization. Please feel free to ask if you need further clarification or share any advice! Thank you!

import React, { useEffect, useState } from "react";
import './Home.css';
// Components
import Header from '../../Components/Header/Header';
import Footer from '../../Components/Footer/Footer';
// Dependencies
import Axios from 'axios';
import { useNavigate, useLocation, useParams } from 'react-router-dom';
// Function
import VerificationCheck from "../../Functions/VerificationCheck";

const Home = () => {
    const navigate = useNavigate();
    const location = useLocation();
    const userLoggedIn = VerificationCheck.CheckLogin();
    const loggedInUser = VerificationCheck.CheckUser();
    const [isLoading, setIsLoading] = useState(false);
    const [posts, setPost] = useState([]);
    const [statusMessage, setStatusMessage] = useState(null);
    const [displayShowMore, setDisplayShowMore] = useState(false);
    const [showMore, setShowMore] = useState(false);

    useEffect(() => {
        if (!userLoggedIn) {
            navigate("/Login", {
                state: {
                    previousUrl: location.pathname,
                }
            });
        } else {
            getAllPost();
        }
    }, [userLoggedIn]);

    const getAllPost = () => {
        const url = process.env.REACT_APP_Backend_URL + "/post/get-post-record";

        Axios.post(url)
            .then((response) => {
                for (var i = 0; i < response.data.length; i++) {
                    if (response.data[i].postsCaption.length > 250) {
                        setDisplayShowMore(true);
                    }
                }
                setPost(response.data);
            })
            .catch((error) => {
                setStatusMessage("Server Side Error");
                setIsLoading(false);
            });
    }

    return (
        <>
            <Header />
            <div className="homeBody">
                <div className="homeForm">
                    {isLoading ?
                        <>
                            <h1>Loading...</h1>
                        </>
                        :
                        <>
                            {statusMessage ?
                                <>
                                    <h1>{statusMessage}</h1>
                                </>
                                :
                                <>
                                    {posts.map(uploadedPost => (
                                        <table key={uploadedPost.postsID}>
                                            <tbody className="postData">
                                                <tr><td><a href="#"><h1 className="title">{uploadedPost.postsTitle}</h1></a></td></tr>
                                                <tr>
                                                    <td>
                                                        <div className="authorDate">
                                                            <h2 className="author">Author: {uploadedPost.postsAuthor}</h2>
                                                            <h3 className="datetime">{uploadedPost.createdOn}</h3>
                                                        </div>
                                                    </td>
                                                </tr>
                                                <tr><td className="btn"><button className="btn" onClick={() => setShowMore(!showMore)}>{showMore ? "Show less" : "Show more"}</button></td></tr>
                                                <tr><td><p className="caption">{showMore ? uploadedPost.postsCaption : `${uploadedPost.postsCaption.substring(0, 250)}${showMore ? "" : "..."}`}</p></td></tr>
                                            </tbody>
                                        </table>
                                    ))}
                                </>
                            }
                        </>
                    }
                </div>
            </div>
            <Footer />
        </>
    );
}

export default Home;

Answer №1

Your current approach is on the right track. Instead of just toggling the setDisplayShowMore state variable, you can create a new object for each individual post with that field.

const getAllPost = () => {
        const url = process.env.REACT_APP_Backend_URL + '/post/get-post-record';

        Axios.post (url)
        .then ((response) => {
            const _data = response.data;
            for (var i = 0; i < _data.length; i++){
                _data[i].displayMore = false;
            }
            setPost(_data);
        })
        .catch((error) => {
            setStatusMessage("Server Side Error");
            setIsLoading(false);
        });
    }
   

This allows you to adjust the number of rows to display in each table by modifying this field. Remember, when updating the table rows, you need to replace the entire posts state variable rather than directly modifying it.

Edit: Check out more details on my point below.

In this scenario, the code changes the displayMore based on user interaction. Instead of maintaining a separate showMore state, you can utilize this field. Integrate this function where you fetch posts or any other similar functions.

const handleShowMore = (post_id) => {
                
                    const current_state = [...posts];
                  
                  const current_post = current_state.find(p => p.postsID === post_id);
                  
                  if(!current_post) {
                  // couldn't find the post, ID's dont match
                  return;
                  }

                  // toggle the current state
                  current_post.displayMore = !current_post.displayMore;
                  setPosts(current_state);
                }        

By utilizing the displayMore field, you can decide which button to display and whether to show ellipses or not.

{posts.map(uploadedPost => (
                            <table>
                                <tbody className="postData" key={uploadedPost.postsID}>
                                    <tr><td><a><h1 className="title">{uploadedPost.postsTitle}</h1></a></td></tr>
                                    <tr>
                                        <td>
                                            <div className="authorDate">
                                                <h2 className="author">Author: {uploadedPost.postsAuthor}</h2>
                                                <h3 className="datetime">{uploadedPost.createdOn}</h3>
                                            </div>
                                        </td>
                                    </tr>
                                    <tr><td className="btn"><button className="btn" onClick={() => handleShowMore(uploadedPost.postsID)}>{uploadedPost.displayMore ? "Show less" : "Show more"}</button></td></tr>
                                    <tr><td><p className="caption">{uploadedPost.displayMore ? uploadedPost.postsCaption : `${uploadedPost.postsCaption.substring(0, 250)}`}{uploadedPost.displayMore ? "" : "..."}</p></td></tr>
                                </tbody>
                            </table>
                        ))}
                    </>
                    }
                </>
                }

I apologize for the messy formatting, it seems Stack Overflow scrambled it somehow.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I created a design for a subscription form that appears aesthetically pleasing in Firefox, however, it does not maintain the same appearance in Opera. Any suggestions on how I can resolve this issue?

Why does my code display differently in Firefox compared to Opera? In Firefox, the height of input/text and input/submit elements are similar. However, in Opera, the height of the input/submit is reduced. This is the HTML code: < ...

Issue with Vue.js input not updating with v-model after input sanitization in watch handler

Recently, while working with Vue 2.6, I came across an unusual issue when trying to sanitize user input. The main culprit seemed to be a custom component that housed the input field. Here's a simplified version of it: <template> <input :na ...

Complete interaction with child processes in Node.js

I have a basic C++ program compiled using the command gcc 1.cpp -o 1.exe. // 1.cpp #include <stdio.h> int main(){ int num = 0; scanf("%d", &num); printf("%d", num + 1000); scanf("%d", &num); printf("\n%d", num + 1000); ...

The JSON output from the gapi (Google Analytics) array in PHP is not displaying any values

I've been utilizing the gapi class within a CodeIgniter website. The implementation I'm using is based on this resource, which returns an array that functions perfectly. To pass this array to my JavaScript, I've been attempting the following ...

beforeunload event confirmation prompt

I am currently working with Laravel and Vue.js to create a multi-step wizard. Within this wizard, I have implemented the onbeforeunload event to prevent any unwanted actions by displaying a confirmation message. However, I am encountering an issue where th ...

Having difficulty adjusting the padding of the Material UI table

I have been using the Table component provided by the material-ui library in my React project. However, I have encountered an issue where each row, including the header, has a padding of 24px on the top and bottom that I am unable to modify or overwrite. D ...

Retrieve information from the form through properties upon submission

Recently, I began my journey in development using react native and encountered a challenge in retrieving the value of an input field through props. Parent class HomeContainerScreen extends Component { state = { userName:'&apos ...

Experience seamless page transitions with React Router v4's sleek animation that smoothly guides you

I implemented a fade-in fade-out transition for routed components using RR4 and ReactCSSTransitionGroup, based on the example provided in https://reacttraining.com/react-router/web/example/animated-transitions While the animations are working, I am facing ...

Retrieve the binary file data that was sent via Postman using Node.js/Express.js

I am currently testing file uploading in my backend system. I am using Postman to send binary data as a file in the request body, and now I need to extract this data from the POST request. req.body The above code snippet returns a binary buffer that look ...

useContext is failing to read values upon initial page load

export const LoginContext = React.createContext(); export const DetailsContext = React.createContext(); function App() { const username = localStorage.getItem("bankDetails"); const [userDetails, setUserDetails] = useState({}); const [isVal ...

What could be causing the issues with the compatibility of <input type="text" and flex properties?

I'm having an issue where the search box expands in size when I apply display:flex in my CSS. Can someone explain why this happens and offer a solution to return the search box to its normal height? Additionally, I would like the search bar and the se ...

Rotating and scaling an image simultaneously using CSS3

I am feeling very puzzled. Why am I unable to simultaneously scale and rotate? Despite my attempts, it seems to be not working: .rotate-img{ -webkit-transform:scale(2,2); -webkit-transform:rotate(90deg); margin-left:20%; margin-top:10%; } ...

What is the best way to prematurely exit from the useEffect hook?

The documentation states that hooks should only be called at the top level of components. With the useEffect API already reserving return for cleanup, I was left wondering how to prematurely exit a useEffect hook to avoid deep nesting of if statements. // ...

Unable to locate _app.js file in nextJs

Currently, I am utilizing npx create-next-app for generating my NextJs project and now I am looking to incorporate global styles using bootstrap Upon downloading bootstrap, the suggestion was to add global styles in pages/_app.js, but I couldn't loca ...

Trouble encountered in aligning two DIVs in a horizontal position

I have been through numerous discussions on the same problem, but none of the solutions seem to work in my case. I am currently working on a section of my website that has 3 small boxes, each containing an image on top and text below. The issue arises when ...

Incorporating react components into haml files with react_component() function

When utilizing the react-rails library, we have the ability to incorporate a react component by using the react_component() function within an .erb file. Is there a method for implementing this same function in a .haml file, or is there an alternative way ...

Utilize the <wbr> tag within FormattedMessage and assign it as a value while coding with TypeScript

Trying out the optional word break tag <wbr> in a message within <FormattedMessage id="some:message" />. Context Some words or texts are too lengthy for certain parent elements on smaller mobile screens, and we have a column layout t ...

Ensure that only valid numbers can be inputted into an HTML number type field

My input number is as follows: <input type="number" id="quantity" name="quantity" (change)="firstRangePointChanged($event)" > I need to ensure that users cannot input invalid values like --99 (--) instead of ...

Unable to smoothly expand Div in React using Tailwind

I'm facing a challenge in animating a div that contains input elements. I want it to expand smoothly - initially, the text area is small and the other two inputs and buttons are hidden. When clicking on the text area, the input and button should be re ...

Adjusting the alignment of text using the "=" symbol

Can you help me align text with the "=" sign, just like in the image below? https://i.sstatic.net/L53k2.png I know I can achieve this using mathjax, but I'd prefer to do it with CSS. However, my current method isn't producing aligned equal sign ...