How we handle modal in Ag Grid React in cellRendererFramework? - reactjs

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

Related

How do you mock child component with custom HTML react jest

Im trying to test a basic component that has a nested Modal component. How could one mock the Modal and test the Modal is successfully populated by values from extraDataInfo object (i.e extraDataInfo?.title)?
export const ExtraDataButtons = ({ extraDataInfo, containerClassName }) => {
const modalSeeMoreTrigger = {
ariaLabel: 'See more',
cssClassName: 'c-extra-data-see-more',
dataAttributes: { seeMore: 'seeMore' },
text: 'See more'
};
return (
<div className={containerClassName}>
<Modal trigger={modalSeeMoreTrigger}>
<div className="c-extra-data-info-cont">
<div className="c-extra-data-number">{extraDataInfo?.offerData}</div>
<div className="c-extra-data-detail">
<div className="c-extra-data-message">
{extraDataInfo?.text && (
<h3 className="c-extra-data-heading">{extraDataInfo?.text}</h3>
)}
{extraDataInfo?.offerDescription && (
<p className="c-extra-data-description">{extraDataInfo?.offerDescription}</p>
)}
</div>
</div>
</div>
<h4 className="c-extra-data-tc-heading" data-test-id="c-extra-data-tc-heading">
{extraDataInfo?.title}
</h4>
<Markdown text={extraDataInfo?.content} />
</Modal>
<button data-test-id="see-more-btn" className="c-extra-data-see-more" type="button">
<Icon svgSource={linearArrowRight} size={20} />
</button>
</div>
);
};

onClick load react component in the same place

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.

Creating a modal in React JS on pre-existing button

I want a modal to open when I click on an info circle on the product info button. I can't figure out how to do this in react after the export default statement.
The export default is important to other events in my code so I wanted to keep that as it is.
export default ({ product, addToBasket, removeFromBasket, openModal}) => {
return (
<div className={styles.tile}>
<div className={styles.tileGrid}>
<div className={styles.imageContainer}>
<FontAwesomeIcon icon={faCamera} />
</div>
<h3 className={styles.shortDescription}>{product.shortDescription}</h3>
<p className={styles.price}>£{product.price}</p>
{product.quantity && (
<p className={styles.quantity}>Quantity: {product.quantity}</p>
)}
{
<div className={styles.modal} onClick={() => openModal(product)}>
<FontAwesomeIcon icon={faInfoCircle} /> Product Info
</div>}
{addToBasket && (
<button className={styles.cta} onClick={() => addToBasket(product)}>
<FontAwesomeIcon icon={faShoppingBasket} /> Add to Basket
</button>
)}
{removeFromBasket && (
<button
className={styles.secondaryButton}
onClick={() => removeFromBasket(product)}
>
Remove from Basket
</button>
)}
</div>
</div>
);
};
Have used the following link but can't get it working in my code: https://www.pluralsight.com/guides/how-to-trigger-modal-for-react-bootstrap

React prevent body from scrolling if popup is open

React prevent body from scrolling if popup is open.
How can i disable the background body from scrolling when the pop up div is open.
function FilterButton() {
let [isOpen, setIsOpen] = useState(false);
return (
<div className='filter-button'>
<div className="name-filter" onClick={() => setIsOpen(!isOpen)}>
<p>Filter</p>
<i class="fas fa-filter"></i>
</div>
{
isOpen ? <div className="background-blur">
<div className="filter-popup">
<p className='filter-by-name'>Filter By Type</p>
<hr />
<div className="filter-types">
<div className="filter">
<input type="checkbox" />
<p></p>
</div>
</div>
<div className="apply-cancel">
<button className="apply">Apply</button>
<button className="cancel" onClick={() => setIsOpen(!isOpen)}>Cancel</button>
</div>
</div>
</div>
: null
}
</div>
)
}
You can use the body-scroll-lock library to help you with that.
Here is how it could work on your component. I haven't tested it tho.
import { useState, useRef, useEffect } from 'react';
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks
} from 'body-scroll-lock';
function FilterButton() {
const [isOpen, setIsOpen] = useState(false);
const popupRef = useRef(null)
useEffect(() => {
if (isOpen) {
popupRef.current && disableBodyScroll(popupRef.current)
} else {
popupRef.current && enableBodyScroll(popupRef.current)
}
}, [isOpen])
return (
<div className="filter-button">
<div className="name-filter" onClick={() => setIsOpen(!isOpen)}>
<p>Filter</p>
<i class="fas fa-filter"></i>
</div>
{isOpen ? (
<div className="background-blur">
<div className="filter-popup" ref={popupRef}>
<p className="filter-by-name">Filter By Type</p>
<hr />
<div className="filter-types">
<div className="filter">
<input type="checkbox" />
<p></p>
</div>
</div>
<div className="apply-cancel">
<button className="apply">Apply</button>
<button className="cancel" onClick={() => setIsOpen(!isOpen)}>
Cancel
</button>
</div>
</div>
</div>
) : null}
</div>
);
}

How to show the content and hide the content conditionally in react using hooks

I am working on a React project that I have to show content and hide the content conditionally when I click the button. For example, I have four buttons, First Button is Frontend, Second Button is Middleware, Third Button is Database, and Fourth Button is Apps.
By Default when I landed on the Home Page Frontend Button should be Highlighted remaining button should be normal. At that time I have to show only Frontend-related frameworks or libraries.
Now when I click Middleware Button then the Middleware Button should be Highlighted At that time I have to show Middleware Frameworks like Node Express etc.
Now when I click Database Button then the Database Button should be Highlighted At that time I have to show Database like Mongo Db, Casandra.
Now when I click Apps Button then the App Button should be Highlighted At that time I have to show Apps like React native, Flutter.
Please help me to achieve this task
This is Home.js
import React, { useState } from 'react';
import './Home.css'
const Home = () => {
return (
<div className='container'>
<div className='row'>
<div className='col-3'>
<button className='btn btn-primary mt-3'>Frontend</button>
</div>
<div className='col-3'>
<button className='btn btn-danger mt-3'>Middleware</button>
</div>
<div className='col-3'>
<button className='btn btn-secondary mt-3'>Database</button>
</div>
<div className='col-3'>
<button className='btn btn-info mt-3'>Apps</button>
</div>
</div>
<div className='row mt-3'>
<div className='col-3'>
<h3>React</h3>
</div>
<div className='col-3'>
<h3>Angular</h3>
</div>
<div className='col-3'>
<h3>Vue</h3>
</div>
<div className='col-3'>
<h3>Ember</h3>
</div>
</div>
</div>
)
}
export default Home
const Home = () => {
const [selected, setSelected] = useState('frontend')
const frontends = ['React', 'Angular', 'Vue']
const middlewares = ['Node', 'Express', 'Hapi']
const databases = ['MongoDB', 'MySQL', 'Casandra']
const apps = ['React Native', 'Flutter']
let showingArr = []
if (selected === 'frontend') {
showingArr = frontends
} else if (selected === 'middleware') {
showingArr = middlewares
} else if (selected === 'database') {
showingArr = databases
} else if (selected === 'apps') {
showingArr = apps
}
return (
<div className='container'>
<div className='row'>
<div className='col-3'>
<button
className='btn btn-primary mt-3'
onClick={() => setSelected('frontend')}
>Frontend</button>
</div>
<div className='col-3'>
<button
className='btn btn-danger mt-3'
onClick={() => setSelected('middleware')}
>Middleware</button>
</div>
<div className='col-3'>
<button
className='btn btn-secondary mt-3'
onClick={() => setSelected('database')}
>Database</button>
</div>
<div className='col-3'>
<button
className='btn btn-info mt-3'
onClick={() => setSelected('apps')}
>Apps</button>
</div>
</div>
<div className='row mt-3'>
{
showingArr.map(item => (
<div className='col-3'>
<h3>{item}</h3>
</div>
))
}
</div>
</div>
)
}
const [show, setShow] = useState(false);
return(
{show ? <content to show when state is true /> : null}
)
here is a more scale able way of doing this . in the future if you want to add new topics of different types for example Pythonwhich can be of type AI , you want have to add an other condition check you can just add your AI toggle button and set onClick as toggleListType('AI')
import React, { useState ,useEffect} from 'react';
import './Home.css'
const Home = () => {
const [listOFtopics,setlistOFtopics]=useState([
{type:'FRONTEND',title:'react'},
{type:'FRONTEND',title:'angular'},
{type:'MIDDLEWEAR',title:'node'},
{type:'MIDDLEWEAR',title:'express'},
])
const [listOFtopicsToDisplay,setlistOFtopicsToDisplay]=useState([])
useEffect(()=>{
//initializing listOFtopicsToDisplay to show FRONEND related topics
setlistOFtopicsToDisplay(listOFtopics.filter(t=> t.type =="FRONTEND"))
},[])
const toggleListType=(type)=>{
setlistOFtopicsToDisplay(listOFtopics.filter(t=> t.type ==type))
}
return (
<div className='container'>
<div className='row'>
<div className='col-6'>
<button onClick={e=>toggleListType('FRONTEND')} className='btn btn-primary mt-3'>Frontend</button>
</div>
<div className='col-6'>
<button onClick={e=>toggleListType('MIDDLEWEAR')} className='btn btn-danger mt-3'>Middleware</button>
</div>
</div>
<div className='row mt-3'>
{
listOFtopicsToDisplay.map(t=><div className='col-3'><h3>Vue</h3</div>)
}
</div>
</div>
)
}
export default Home

Resources