Rendering multiple componets in a table react - javascript

I have a component that renders a table with data from a database, I am experiencing a problem where I cant render the second component called EditButton bottom of the code, I managed to render the 1st component DeleteButton bottom of the code, but when I try to render another button I get errors. The goal is to render another button in the table. Thanks in advance :)
import React, { useState } from 'react';
import { Button } from 'semantic-ui-react';
import { currentloginid } from '../login/loginid.js';
import { deletequestion } from '../question/deletequestion.js';
import { editanswer } from '../answer/editanswer.js';
export const ViewQuestionComponent = () => {
let [state, setState] = useState([]);
const handleViewQuestion = async () => {
try {
const response = await fetch('http://localhost/gotaquestion/api/api.php?action=viewquestion', {
method: 'GET',
credentials: 'include'
});
const data = await response.json();
const result = await data;
setState(data);
} catch (e) {
console.log(e);
}
}
return (
<div>
<ViewQuestion onClick={handleViewQuestion} />
<div id="questions">
<Table rows={state}>
<DeleteButton onClick={deletequestion} />
</Table>
</div>
</div>
);
};
export function ViewQuestion({onClick}) {
return (
<Button onClick={onClick}>View Question</Button>
);
}
export default ViewQuestion;
const Table = ({ rows, setIdTobeDeleted, children }) => (
<table className="ui single line table">
<tbody>
{rows.map((row) => (
<tr key={row.questionid}>
<td>{row.question}</td>
<td>{row.timestamp}</td>
<td>{row.catagories}</td>
<td>{row.answer === null ? "Not Answered" : row.answer}</td>
<td>
{React.cloneElement(children, { questionid: row.questionid })}
</td>
<td>
//I want the EditButton to render there instead on DeleteButton
{React.cloneElement(children, { questionid: row.questionid })}
</td>
<td>{row.questionid}</td>
</tr>
))}
</tbody>
</table>
);
const EditButton = ({ questionid, onClick }) => (
<button
className="ui negative basic button"
onClick={() => onClick(editanswer)}
>Edit Question</button>
);
const DeleteButton = ({ questionid, onClick }) => (
<button
className="ui negative basic button"
onClick={() => onClick(questionid)}
>Delete Question</button>
);

I think in your view you have missed the edit button.
Please consider changing
return (
<div>
<ViewQuestion onClick={handleViewQuestion} />
<div id="questions">
<Table rows={state}>
<DeleteButton onClick={deletequestion} />
</Table>
</div>
</div>
);
to
return (
<div>
<ViewQuestion onClick={handleViewQuestion} />
<div id="questions">
<Table rows={state}>
<DeleteButton onClick={deletequestion} />
</Table>
<Table rows={state}>
<EditButton onClick={editanswer} />
</Table>
</div>
</div>
);

Related

how to create the input div on clicking the reply button of a comment below that particular comment using react

I want on clicking the reply button the div to write the reply to come
I tried to create a seperate component for reply textarea but as I am a beginner in react I am not able to get an idea how to do it.
Comment.js
import Userdata from "./data.json";
import Score from "./Score";
import Person from "./person";
import Reply from "./Reply";
const Comment = () => {
return (<div className="sample">{
Userdata.comments.map((comment, index) => {
return (
<div key={comment.id}>
<div className="comment">
<Score score={comment.score} />
<div>
<Person user={comment.user} />
<span className="time">{comment.createdAt}</span>
<Reply index={index} />
<p>{comment.content}</p>
</div>
</div>
{comment.replies.map((reply) => {
return (
<div key={reply.id}>
<div className="comment reply">
<Score score={reply.score} />
<div>
<Person user={reply.user} />
<span>{reply.createdAt}</span>
<Reply />
<p>{reply.content}</p>
</div>
</div>
</div>
);
})}
</div>
);
})
}
</div>
);
}
export default Comment;
Reply Component
const Reply = (props) => {
const handleClick = () => {
console.log(`reply of ${props.index}`)
}
return (
<div onClick= {handleClick} className="btn-reply">
<img className="reply-icon" src="images/icon-reply.svg" alt="reply" />
<span>Reply</span>
</div>
);
}
export default Reply;

How to render a react component and replicate them from the click event

I want to make multiple copies of Form2 React Component with click event, but the code not working as I want, I am new in react so can anybody help me.
const Comform = () => {
const Form2 = () => {
return(
<div className="card" id='form-card2'>
<input className="form-check-input" type="checkbox" value="" id="options-check" onClick={Optionscheck} />
</div>
);
}
const Replica = () {
<Form2/>
}
return(
<button type="button" className="btn btn-success" onClick={Replica}>Add</button>
);
}
Keep a state as the replica counter and render the number of items you want using Array.from and Array.prototype.map.
Try like this:
const Form2 = () => {
return (
<div className="card" id="form-card2">
<input
className="form-check-input"
type="checkbox"
value=""
id="options-check"
// onClick={Optionscheck}
/>
abcd
</div>
);
};
const Replica = () => {
const [replicaCount, setReplicaCount] = React.useState(0);
return (
<div>
<button
type="button"
className="btn btn-success"
onClick={() => setReplicaCount((prev) => prev + 1)}
>
Add
</button>
{Array.from({ length: replicaCount }).map((_, index) => (
<Form2 key={index}/>
))}
</div>
);
};
ReactDOM.render(<Replica />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Summary
You would have to create a handler for the replica button and a state that tracks how often the button was clicked, so that you are able to render as much form items as the button was clicked.
Example
import { useState } from "react";
import "./styles.css";
const FormItem = () => (
<div className="formItem">
<label>Check me</label>
<input type="checkbox" />
</div>
);
const ReplicaButton = ({ addFormItem }) => (
<button onClick={addFormItem}>Add more</button>
);
export default function Form() {
const [formCount, setFormCount] = useState(1);
const addFormItem = () => setFormCount(formCount + 1);
return (
<div>
<form className="formius">
{Array(formCount)
.fill(null)
.map(() => (
<FormItem />
))}
</form>
<ReplicaButton addFormItem={addFormItem} />
</div>
);
}

How to pass data from a table row and pass it to another component when it renders?

I have a component that shows a table and one of its columns have a field Actions which has buttons (view, edit, delete etc.). On button click, I need to render another component (component is a popup) and pass the data from the table so that it displays the data in some form which I need to further add.
I have managed to get the current data from its row by passing in onClick. I tried to use state for another component to render but it didn't work out. I'm using Semantic-UI React components to display the button with animations.
Here is the code that has the table,
const MainContent = () => {
const [actions, setActions] = useState(false);
const handleView = (rowData) => {
console.log(rowData);
setActions(true);
if (actions == true) return <ParentView />;
};
....
....
const contents = (item, index) => {
return item.routeChildEntry ? (
<>
<tr key={index}>
<td>{item.appName}</td>
<td></td>
<td>{item.createdTs}</td>
<td>{item.pattern}</td>
<td></td>
<td></td>
<td></td>
<td>
<Button animated onClick={() => handleView(item)}>
<Button.Content visible>View</Button.Content>
<Button.Content hidden>
<Icon name="eye" />
</Button.Content>
</Button>
</td>
</tr>
{item.routeChildEntry.map(routeContents)}
</>
) : (
....
....
....
);
};
return (
<div>
....
{loading ? (
<div className="table-responsive">
<table className="table">
<thead>
<tr>
<th>AppName</th>
<th>Parent_App</th>
<th>Created_Date</th>
<th>Req_Path</th>
<th>Resp_Code</th>
<th>Resp_Content_Type</th>
<th>Resp_Delay</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{data.map((routes, index) => {
return routes.map(contents, index);
})}
</tbody>
</table>
</div>
) : (
....
....
)}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default MainContent;
Below is the component to render on button click,
import React from "react";
import Popup from "reactjs-popup";
import { Icon } from "semantic-ui-react";
const Parent = (props) => {
return (
<Popup trigger={<Icon link name="eye" />} modal closeOnDocumentClick>
<h4>in parent</h4>
</Popup>
);
};
export default Parent;
How can I render the other component and pass data to it on button click?
Data can be passed to other components as props.
For example, if your component is <ParentView />, and the data you are passing is contained in the variable rowData, you can pass it as:
<ParentView dataPassedByAkhil = {rowData}/>
Then in your ParentView component,
export default function ParentView({dataPassedByAkhil}) {
console.log(dataPassedByAkhil);
Alternatively, you can accept the data as props as below
export default function ParentView(props) {
console.log(props.dataPassedByAkhil);
If you want to open and close another popup, you can pass a state just like above.
<PopupComponent open={stateSetForPopupByParent}/>
Example of popup using state.
Updated link above with how to pass data to the dialog from rows of buttons
Here is the full code:
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
const [valueofRow, setValueOfRow] = React.useState();
const handleClickOpen = (value) => {
setValueOfRow(value);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("John");
}}
>
Row 1 - value is John
</Button>
<br />
<br />
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("Sally");
}}
>
Row 2 Value is Sally
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="edit-apartment"
>
<DialogTitle id="edit-apartment">Edit</DialogTitle>
<DialogContent>
<DialogContentText>Dialog fired using state</DialogContentText>
<h1>{valueofRow} was clicked and passed from the row</h1>
<TextField
autoFocus
margin="dense"
id="field"
label="some field"
type="text"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
</div>
);
}

How to change the button text on click

import React from "react";
function ToDoItem(props) {
function but(){
document.getElementById('testBtn').value='ok'
}
return (
<div
>
<li>{props.text} <button class="deletebtn" onClick={() => {
props.onChecked(props.id);
}}><span>Delete</span></button>
</li>
<hr/>
<input type="button" value="Test" id="testBtn" onclick={but}/>
</div>
);
}
export default ToDoItem;
I wrote this function to change the value of the id from from "Test" to "ok", but I donot know why it is not working. When I use onclick="but()" instead of onclick={but}, it says the function but() is unused. I am not why is this not working. Please help
This is how you do it in React. You dont mix react, with DOM manipulation:
import React, {useState} from "react";
function ToDoItem(props) {
const [buttonText, setButtonText] = useState('Test');
return (
<div>
<li>
{props.text}
<button
class="deletebtn"
onClick={() => {
props.onChecked(props.id);
}}
>
<span>Delete</span>
</button>
</li>
<hr />
<input
type="button"
value={buttonText}
id="testBtn"
onClick={() => setButtonText("Ok")}
/>
</div>
);
}
export default ToDoItem;
And an, update for follow-up question. With the styling it depends what kind of styling you use in your react application. But you could use inline styling to get the behaviour you want. I for one use styled components when working in React...here's an updated code.
import React, { useState } from "react";
function ToDoItem(props) {
const [buttonText, setButtonText] = useState("Test");
const [buttonColor, setButtonColor] = useState("red");
const changeButton = () => {
setButtonText(buttonText === "Test" ? "Ok" : "Test");
setButtonColor(buttonColor === "red" ? "blue" : "red");
};
return (
<div>
<li>
{props.text}
<button
class="deletebtn"
onClick={() => {
props.onChecked(props.id);
}}
>
<span>Delete</span>
</button>
</li>
<hr />
<input
style={{ backgroundColor: buttonColor }}
type="button"
value={buttonText}
id="testBtn"
onClick={changeButton}
/>
</div>
);
}
export default ToDoItem;
Adding to my comments, your code reimplemented with hooks.
import React, { useState } from "react";
function ToDoItem(props) {
const [value, setValue] = useState('Test');
function but(){
setValue('ok');
}
return (
<div>
<li>{props.text} <button class="deletebtn" onClick={() => {
props.onChecked(props.id);
}}><span>Delete</span></button>
</li>
<hr/>
<input type="button" value={value} id="testBtn" onclick={but}/>
</div>
);
}
export default ToDoItem;

Opposite react component state changing

I have a simple login form component that when I click, would like for the form to disappear and only display my json. I am a little rusty with working with react state, and appear to have the opposite effect of what I am trying. When I click on my button event, the json I am displaying will toggle appearing and disappearing, but the form stays static. I need the form to disappear and the page to populate with my grid.
Here is my components
index.jsx
import React from 'react';
import SignUp from '../SignUp';
import Cards from '../Articles/Cards';
export default class Gecko extends React.Component {
constructor(props) {
super(props);
this.state = { requestedPostsThatWeGotFromGecko: null, }
this.clickMe = this.clickMe.bind(this)
}
clickMe = () => {
const {requestedPostsThatWeGotFromGecko} = this.state;
this.setState({ requestedPostsThatWeGotFromGecko: !requestedPostsThatWeGotFromGecko })
}
render() {
console.log(this.state);
return (
<div className='gecko'>
<SignUp login={() => this.clickMe()}/>
{this.state.requestedPostsThatWeGotFromGecko &&
<Cards />
}
</div>
);
}
}
Sign up component
import React from 'react';
export default class SignUp extends React.Component {
render() {
const onClick = () => {
this.props.login();
console.log('rich');
}
return (
<div className='sign-up'>
<table className='sign-up-form'>
<tbody>
<div class="gecko-signup__tabs"><button id="gecko-signup" data-selected="yes">Sign Up</button><button id="gecko-login" data-selected="">Log In</button></div>
<tr>
<td>
<p id="signUpFree">Sign Up for Free</p>
</td>
</tr>
<div id="inputs-section">
<tr>
<td><input id="first" placeholder="First Name*" /></td>
<td><input id="last" placeholder="Last Name*" /></td>
</tr>
</div>
<tr>
<td colSpan="2"><input placeholder="Email Address*" /></td>
</tr>
<tr>
<td colSpan="2"><input placeholder="Set A Password*" /></td>
</tr>
<tr>
<td colSpan="2"><input id="getStarted" type="submit" value="Get Started" onClick={onClick}/></td>
</tr>
</tbody>
</table>
</div>
);
}
}
CardSetup component
import React from 'react';
import SignUp from '../SignUp';
export default class Articles extends React.Component {
constructor(props) {
super(props);
this.state = {
requestedPostsThatWeGotFromGecko: [],
}
}
componentDidMount(){
const api = 'https://5d445466d823c30014771642.mockapi.io/api/v1/products';
const request = new Request(api);
// Fetch isn't browser compatible...Might should fix.
fetch(request)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
throw new Error('Something went wrong on api server!');
};
}).then(response => {
this.setState({
requestedPostsThatWeGotFromGecko: response
});
})
.catch(error => {
console.error(error);
});
}
render() {
return(
<div className='articles'>
{this.state.requestedPostsThatWeGotFromGecko.map(product => {
return (
<div className='flex-grid'>
<div className="card">
<div className="overflow">
<img className='productImage' src={product.image}></img>
</div>
<div className='card-body'>
<p id='name'>{product.name}</p>
<p id='description'>{product.description}</p>
<p id='price'>{product.price} </p>
</div>
</div>
</div>
);
})
}
</div>
)}}
Final Cards component
import React from 'react';
import Articles from './CardSetup';
export default class Cards extends React.Component {
render() {
return(
<div className="cards">
<h2>Products</h2>
<div className="column">
<Articles />
</div>
<div className="column">
<Articles />
</div>
<div className="column">
<Articles />
</div>
<div className="column">
<Articles />
</div>
</div>
);
}
}
I am pretty sure that I am setting the state incorrectly somewhere along the line after I press the button. I am thinking about jquery and wanting to "hide" the element but I know that is incorrect with react. Any help is greatly appreciated.
Conditionally render Cards or Signup based on truthy/falsey value of requestedPostsThatWeGotFromGecko.
render() {
const { requestedPostsThatWeGotFromGecko } = this.state;
return (
<div className="gecko">
{requestedPostsThatWeGotFromGecko ? (
<Cards />
) : (
<SignUp login={() => this.clickMe()} />
)}
</div>
);
}
Probably this is what you want:
render() {
return (
<div className='gecko'>
{!this.state.requestedPostsThatWeGotFromGecko &&
<SignUp login={() => this.clickMe()}/>
}
{this.state.requestedPostsThatWeGotFromGecko &&
<Cards />
}
</div>
);
}
If I understood correctly, you want to toggle between the Signup form and Cards based on requestedPostsThatWeGotFromGecko state variable.
So you can do something like this in your index.jsx:
render() {
return (
<div className='gecko'>
{this.state.requestedPostsThatWeGotFromGecko ?
<Cards /> :
<SignUp login={() => this.clickMe()} />
}
</div>
);
}
All you have to do is conditionally render the SignUp page on the basis of flag requestedPostsThatWeGotFromGecko.
Note: Important thing is you have to initialize it with false and make it true on the click from the SignUp page.
constructor(props) {
super(props);
this.state = { requestedPostsThatWeGotFromGecko: false };
this.clickMe = this.clickMe.bind(this)
}
render() {
const { requestedPostsThatWeGotFromGecko } = this.state;
return (
<div className="gecko">
{requestedPostsThatWeGotFromGecko ? (
<Cards />
) : (
<SignUp login={() => this.setState({ requestedPostsThatWeGotFromGecko: true })} />
)}
</div>
);
}

Categories