onClick load react component in the same place - reactjs

I have a panel with 3 buttons, i want to make onclick on every button, a different component will appear in the same place. How can this logic be done?
<AddNotification />
<EditNotification />
<DeleteNotification />
const AdminPanel = () => {
return (
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
<Button type="submit">Add Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Edit Notification</Button>
</div>
<div className="form-group">
<Button type="submit">Delete Notification</Button>
</div>
</form>
</Card>
)
}

#MLDC No i don't have another divs, i want to replace the buttons with the crossponding component. For example: onclick on Add, then Add component will appears instead of the buttons.
In that case, create a boolean state for every Panel that you have (I created 3 so that you could open the panels simultaneously),
const [isAddPanelOpen, setIsAddPanelOpen] = useState(false);
const [isEditPanelOpen, setIsEditPanelOpen] = useState(false);
const [isDeletePanelOpen, setIsDeletePanelOpen] = useState(false);
Next, apply this to every button
<Button onClick={setIsAddPanelOpen(prevState=>!prevState)}>Add Notification</Button>
<Button onClick={setIsEditPanelOpen(prevState=>!prevState)}>Edit Notification</Button>
<Button onClick={setIsDeletePanelOpen(prevState=>!prevState)}>Delete Notification</Button>
Lastly, Refactor your html to
<div className="form-group">
{isAddPanelOpen ? <AddNotification/> : <Button type="submit">Add Notification</Button>}
</div>
<div className="form-group">
{isEditPanelOpen ? <EditNotification/> : <Button type="submit">Edit Notification</Button>}
</div>
<div className="form-group">
{isDeletePanelOpen ? <DeleteNotification/> :<Button type="submit">Delete Notification</Button>}
</div>

Try this if you want to display one component at a time and hide the others when you click a button
const AdminPanel = () => {
const [componentToDisplay, setComponentToDisplay] = useState("")
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className="form-group">
{componentToDisplay !== "add ? (
<Button type="submit" onCLick={() => setComponentTodisplay("add")}>Add Notification</Button>)
:(<AddNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "edit ? (
<Button type="submit" onCLick={() => setComponentTodisplay("edit")}>Edit Notification</Button>)
:(<EditNotification />)}
</div>
<div className="form-group">
{componentToDisplay !== "delete ? (
<Button type="submit" onCLick={() => setComponentTodisplay("delete")}>Delete Notification</Button>)
:(<DeleteNotification />)}
</div>
</form>
</Card>
</>
)
}
Or if you want to be able to replace every buttons, use this logic with one state per button
const AdminPanel = () => {
const [addNotif, setAddNotif] = useState(false)
const [editNotif, setEditNotif] = useState(false)
const [deleteNotif, setDeleteNotif] = useState(false)
return (
<>
<Card className={classes.input}>
<div><h1>Notification Panel</h1></div>
<form>
<div className={`form-group ${editNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!addNotif ? (
<Button type="submit" onCLick={() => setAddNotif(true)}>Add Notification</Button>)
:(<AddNotification setAddNotif={setAddNotif} />)}
</div>
<div className={`form-group ${addNotif || deleteNotif ? "display: none" : "display: flex"}`}>
{!editNotif ? (
<Button type="submit" onCLick={() => setEditNotif(true)}>Edit Notification</Button>)
:(<EditNotification setEditNotif={setEditNotif} />)}
</div>
<div className={`form-group ${addNotif || editNotif ? "display: none" : "display: flex"}`}>
{!deleteNotif ? (
<Button type="submit" onCLick={() => setDeleteNotif(true)}>Delete Notification</Button>)
:(<DeleteNotification setDeleteNotif={setDeleteNotif} />)}
</div>
</form>
</Card>
</>
)
}
Then in your component
const AddNotification = ({setAddNotif}) => {
...
return (
...
<button onCLick={() => setAddNotif(false)}>back</button>
...
)
}
Same logic for the other components

To achieve this logic you need to manage which component is displayed using a state.
This means:
Attribute an arbitrary id to each component.
Store the id of the active component in a useState hook.
Use conditional rendering to display the component that match the current state.
Update the state to the corresponding Id when clicking on each button.
A small example
const [activePanel, setActivePanel] = React.useState(0)
let currentPanel = <Panel0 />
switch(activePanel){
case 0:
currentPanel = <PanelO />
case 1:
currentPanel = <Panel1 />
// Continue as needed
}
return (
<div>
<CurrentPanel/>
<button onClick={() => setActivePanel (0)}> Panel 0 </button>
<button onClick={() => setActivePanel (1)}> Panel 1 </button>
// And so on
</div>
)
You can further refine this by extracting the switch statement into its own component that takes the activePanel as a prop.

Related

Retrieve form input values using React Children as a wrapper

I need to retrieve the input form data using the wrapper save button (Togglable component) and not a submit button inside a form component.
I have this form.
const BasicDataForm = () => {
return (
<form>
<div>
<label htmlFor="nameInput">Your Name: </label>
<input placeholder="Write your name here" type="text" id="nameInput" />
</div>
<div>
<label htmlFor="ageInput">Your Age: </label>
<input placeholder="Write your age here" type="number" id="ageInput" />
</div>
</form>
);
};
And the wrapper
const Togglable = ({ title, children }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button>Save</button> {/* This button needs to retrieve all input form data from children */}
<button onClick={() => setVisible(false)}>Close</button>
{children}
</div>
</header>
);
};
And the main component
const App = () => {
return (
<>
<h1>Form Wrapper</h1>
<Togglable title="Basic Data Form">
<BasicDataForm />
</Togglable>
</>
);
};
I don't know if it's necessary to add a useState inside the form component. I also tried adding a new prop in the Togglable component that bind the onClick event of the save button to the onSubmit event of the form, but not work because there is no submit button inside form component.
The solution was much easier than I thought. You only need to wrap the entire children inside a <form> label and render only the content of the inputs. For every children a button will be added and you will manage the form outside the wrapper.
const Togglable = ({ title, children, handleSubmit }) => {
const [visible, setVisible] = useState(false);
const hideWhenVisible = { display: visible ? 'none' : '' };
const showWhenVisible = { display: visible ? '' : 'none' };
return (
<header>
<h2>{title}</h2>
<div style={hideWhenVisible}>
<button onClick={() => setVisible(true)}>Show</button>
</div>
<div style={showWhenVisible}>
<button onClick={() => setVisible(false)}>Close</button>
<form onSubmit={handleSubmit}>
{children}
<button type="submit">Save</button>
</form>
</div>
</header>
);
};

How my button can move under each new added sections? For now it's placed above all sections

How can I modify my code in order to get a dynamic +Add Invitee button which will move down the last section each time you add fields? For now, it appears above all blocks.
export default function App() {
const [menu, setMenu] = useState("");
return (
<>
<button type="button" onClick={addInvitee}>
+Add Invitee
</button>
<form onSubmit={handleSubmit}>
{invited.map(({ age, email, id, location, name }, index) => (
<div key={id}>
<div className="grid grid-cols-3 gap-5">
<label className="mr-3 h-6 text-md font-bold">
Names:
<input
type="text"
value={name}
placeholder="Names"
name="name"
onChange={updateInvitee(id)}
/>
</label>
...
{!!index && (
<button type="button" onClick={() => removeInvitee(id)}>
Remove
</button>
)}
</div>
</div>
))}
</form>
</>
);
}
Here is my:
code
To achieve that you just need to take the button down under the form.
export default function App() {
const [menu, setMenu] = useState("");
return (
<>
<form onSubmit={handleSubmit}>
{invited.map(({ age, email, id, location, name }, index) => (
<div key={id}>
<div className="grid grid-cols-3 gap-5">
<label className="mr-3 h-6 text-md font-bold">
Names:
<input
type="text"
value={name}
placeholder="Names"
name="name"
onChange={updateInvitee(id)}
/>
</label>
...
{!!index && (
<button type="button" onClick={() => removeInvitee(id)}>
Remove
</button>
)}
</div>
</div>
))}
</form>
<button type="button" onClick={addInvitee}>
+Add Invitee
</button>
</>
);
}
also you can style the button or wrap it with a div for more complex styling to achieve the example from the photo you shared.
here is alink for a working example: codesandbox

How we handle modal in Ag Grid React in cellRendererFramework?

I have 2 buttons in Ag Grid table in Actions Column. How can I call function, on click of Approve Button in Modal ?
Thanks in Advance
PFB my code -
=>> Ag Grid Component =
const AgGridComp = () => {
const [tableData,setTableData] = useState([{"column1":"Value 1","column2":"Value 2"},{"column1":"Value 3","column2":"Value 4"}])
return(
<>
<div className="ag-grid-data">
<AgGridReact
rowData={tableData}>
<AgGridColumn field="column1" headerName="Column 1"></AgGridColumn>
<AgGridColumn field="column2" headerName="Column 2"></AgGridColumn>
<AgGridColumn headerName="Actions" cellRendererFramework={Actions}></AgGridColumn>
</AgGridReact>
</div>
</>
)
}
==>> Actions Code ==
const Actions = (props) => {
return(
<>
<button className="btn btn-success">Approve</button>
<button className="btn btn-danger">Reject</button>
</>
)
}
==>>Modal Code ==
const ActionsModal = () => {
return(
<>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-title">
<h4>Are you sure to Approve ?</h4>
</div>
<div className="modal-footer">
<button className="btn btn-default">Cancel</button>
<button className="btn btn-success">Approve</button>
</div>
</div>
</div>
</>
)
}

Dynamic add Image and data with Ant-Design and ReactJs

I can't add an image while executing. When adding an image, the image does not appear, I use a dynamic form with the same inputs when adding a form which will later be stored by looping, but I have problems when adding images. I use a plugin from ant design.
Here's the code.
import React,{useState} from 'react'
import { Button,Form,Input } from 'antd';
import {
PlusOutlined,
MinusCircleOutlined,
} from '#ant-design/icons';
function Ad_abhb() {
const [Img1,setImg] = useState([]);
const i = 0;
const AddImg4 = (i) =>{
const [imgPrev1,setImgPrev1] = useState('');
const ImgC1=(e)=>{
const reader = new FileReader();
const vImg = e.target.files[0];
setImgPrev1(URL.createObjectURL(vImg));
reader.readAsDataURL(vImg);
reader.onload = () => {[...setImg(reader.result)]}
}
return(<>
<Form.Item className='imgHobi'>
<Input id={'uImg4'+i.kd} type="file" accept=".jpg,.jpeg,.png" onChange={ImgC1} hidden />
<label htmlFor={'uImg4'+i.kd}>
{imgPrev1.length >= 1 ?<>
<div className='imgLoad'>
<img src={imgPrev1} className='getImg' alt=''/>
</div>
</>:<>
<div className='imgLoad'>
<div className='UpImg'>
<div className='UpCore'>
<PlusOutlined style={{fontSize:'20px'}}/>
</div>
</div>
</div>
</>}
</label>
</Form.Item>
</>)
}
const SimpanA4=()=>{
console.log(Img1)
}
return (<>
<h1>hobi</h1>
<div className='konten'>
<Form >
<Form.List name='Hobi'>
{(fields, { add, remove }) => (<>
{fields.map((field,i)=>{
return(
<div key={field.key} className='cardAdminMod hobiList' >
<AddImg4 kd={i}/>
<Form.Item className='inputHobi' name="Hobi" {...field}>
<Input />
</Form.Item>
{fields.length > 1 ? <div className='rmHobi'><MinusCircleOutlined onClick={() => remove(field.name)} /></div>: null}
</div>)
})}
<Form.Item className='addPlusHobi'>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add Data
</Button>
</Form.Item>
</>)}
</Form.List>
</Form>
</div>
<div className="titleAdmin butSide">
<Button onClick={SimpanA4}>Save</Button>
</div>
</>)
}
export default Ad_abhb;
So, can anyone help me?

How to pass state properties from component to component

I am currently learning React and I am trying to create a basic todo list app. I am facing an issue in the understanding of how passing data from component to component.
I need that when I add a task in the modal of my home component it gets added in the "pub" state of my public task component in order for the task to be rendered.
I joined the code of both components,
Hope someone can help me :)
function PublicTask (){
const [pub,setPub] = useState([{id: 1, value : "test"},{id: 2, value : "test2"}]);
function ToDoPublicItem() {
const pubT = pub.map(value =>{
return(
<div className= 'pubTask-item'>
<li>{value.value}</li>
</div>
)
});
return(
<div>
<div>
{pubT}
</div>
</div>
);
}
return(
<div className= 'item-container'>
<h2 style={{color:'white'}}>Public Tasks</h2>
<ToDoPublicItem/>
</div>
);
}
export default PublicTask;
function Home() {
const [show,setShow] = useState(false);
const [pubTask,setPubTask] = useState([]);
function openModal() {
setShow(true);
}
function Modal(){
const[textTodo, setTextTodo] = useState('')
const addItem = () => {
const itemTopush = textTodo;
pubTask.push(itemTopush);
}
return(
<div className='modal'>
<div className = 'modal-title'>
<h2>ADD A TODO</h2>
<hr></hr>
</div>
<div className= 'modal-body'>
<input type='text' onChange = {(e) => setTextTodo(e.target.value)}/>
<input type="checkbox" id="pub" value ='public'/>
<label Htmlfor="pub">Public</label>
<input type="checkbox" id="priv" value= 'private '/>
<label Htmlfor="riv">Private</label>
<hr></hr>
<Button id='button-add' size='large' style={{backgroundColor : 'white'}} onClick={()=> addItem()}>ADD</Button>
<hr></hr>
<Button id='button-close' size='large' style={{backgroundColor : '#af4c4c'}} onClick= {()=> setShow(false)} >CLOSE</Button>
</div>
</div>
)
}
return(
<div>
<h1 style={{textAlign:'center'}}>You are logged in !</h1>
<div>
<button id='button-logout' onClick = {() => firebaseApp.auth().signOut()}>Logout</button>
</div>
<div>
<Fab color="primary" aria-label="add" size = 'large' onClick = {() => openModal()}>
<Add/>
</Fab>
{show ? <Modal/> : <div></div>}
</div>
<div>
<Router>
<div className='pub-container'>
<Link to='/publicTasks'>Public Tasks </Link>
</div>
<div className='ongo-container'>
<Link to='/onGoingTasks'>On Going Tasks </Link>
</div>
<div className='finish-container'>
<Link to='/finishedTasks'>Finished Tasks </Link>
</div>
<Route path='/publicTasks' component = {PublicTask}/>
<Route path='/onGoingTasks' component = {OngoingTask}/>
<Route path='/finishedTasks' component = {FinishedTask}/>
</Router>
</div>
</div>
);
}
export default Home;
You can share data between react components like this:
const [value, setValue] = useState("test"); // data that you want to share
return (
<Parent data={value}> // pass data to parent in your child component
);
<h1>{this.props.data}</h1> // do something with the data in the parent component

Resources