Open popup on DataTable row click in ReactJS - javascript

I'm using reactjs-popup and react-data-table-component npm libraries and I want to open a pop-up window when a row is clicked.
This is my code:
onRowClicked = (rowData,e) => {
return (<Popup
trigger={/*e.target.value*/}
modal>
{
close => (
<div>
// some code
</div>
)
}
</Popup>)
}
render() {
return (
<DataTable
title={title}
columns={columns}
data={data}
highlightOnHover={true}
pointerOnHover={true}
onRowClicked={this.onRowClicked}
noDataComponent='No content'
/>
)
}
Is it possible to bind the trigger attribute of Popup to the clicked row?

One Naive way to do this would be by putting the table details in the pop trigger
for instance
render() {
let SongList = this.state.Songs.map(({Artist,Title, Album, Id}, index) => {
return (
<Popup modal trigger={<tr key={Id} >
<td>{index+1}</td>
<td>{Artist}</td>
<td>{Title}</td>
<td>{Album}</td>
</tr>}>
{close => <Content4 close={close} />}
</Popup>
);
});
return(
<>
{SongList}
</>
);
}
It works but it is not the most neat or optimal code

Related

Create custom TabPane using react-bootstrap

I would create custom Tab Form from JSON, using React and boostrap. Using this function my code work correctly.
function DisplayForm(props) {
return(
<div className="row">
<Tabs className="mb-3">
{Array.from(new Map(Object.entries(json))).map((data) => (
<Tab eventKey={data[0]} title={data[0]}> </Tab>
))}
</Tabs>
</div>
);
}
}
data[0] is the tabName.
Now, I would create custom tab, based on json value. For example, something, like this:
function DisplayCustomTab(props) {
return(
<div className="row">
<TabContainer className="mb-3">
<TabContent>
{Array.from(new Map(Object.entries(json))).map((data) => (
<>
{(() => {
if(myCondition ) {
return(
<>
<CreateTAB data={data[0]} />
</>
)
}
})()}
</>
))}
</TabContent>
</TabContainer>
</div>
);
}
function CreateTAB(props) {
console.log("tab name: " + props.data); // this line works
return(
<TabPane eventKey={props.data} title={props.data}> </TabPane>
);
}
I using TabPane, TabContent and TabContainer because using Tab and Tabs I get following error:
component is not meant to be rendered! It's an abstract component that is only valid as a direct Child of the `Tabs` Component. For custom tabs components use TabPane and TabsContainer directly
Anyone can explain where I'm wrong? Thank you

HTML elements not rendering on Gatsby website

What I am doing:
Creating my first website in Gatsby.js. Trying to render an HTML element "onClick" of a navigation link. When someone clicks one of the links, I want it to show a dropdown menu.
export function DropDownMenu(props) {
return (
<p>{props}</p>
)
}
const Header = () => {
// const [open, setOpen] = useState(false);
return (
<Nav>
<StyledLinkBox to="/"><Logo/></StyledLinkBox>
<Bars />
<NavMenu>
{headerMenuData.map((item, index, dropdown) => (
<NavLink to={item.link} key={index} onClick={() => {
item.dropdown.map((item, index) => (
<DropDownMenu props={item} key={index}/>
))}
}>
{item.title}
</NavLink>
))}
<StyledButton>Early Access</StyledButton>
</NavMenu>
</Nav>
)
}
Notes:
I have tried to use useState to call another function here, but that doesn't seem to work, as then you have to click twice for anything to happen.
If you replace <DropDownMenu...> within the map function with a console.log, it will print out all the elements that need to appear, which is strange.
So if it can do that, and the mapping function is working correctly, why can't I see <p>{props}</p> for every item?
Use:
export function DropDownMenu({props}) {
return (
<p>{props}</p> /* same as props.props */
)
}
const Header = () => {
// const [open, setOpen] = useState(false);
return (
<Nav>
<StyledLinkBox to="/"><Logo/></StyledLinkBox>
<Bars />
<NavMenu>
{headerMenuData.map((item, index, dropdown) => (
<NavLink to={item.link} key={index} onClick={() => {
item.dropdown.map((item, index) => (
<DropDownMenu props={item} key={index}/>
))}
}>
{item.title}
</NavLink>
))}
<StyledButton>Early Access</StyledButton>
</NavMenu>
</Nav>
)
}
You are sending item as props and the component is also, by default, is getting props (if you send it), so you need to restructure it or access the data by props.props.
You can do:
<DropDownMenu item={item} key={index}/>
And:
export function DropDownMenu({item}) {
return (
<p>{item}</p> /* same as props.item */
)
}
For a more succinct approach.

How to show the dialog everywhere in the app on clicking a button using react and typescript?

i want to display a dialog on clicking additem and addbooks button using react and typescript.
what i am trying to do?
I want to display a dialog on clicking additem button or addbooks button . this dialog will have hide button. on clicking this hide button the dialog should never appear again for the session.
Below is the code,
function MainComponent () {
const [showDialog, setShowDialog] = React.useState(false);
const openDialog = () => {
setShowDialog(true);
};
const hideDialog = () => {
setShowDialog(false);
};
return (
<Route
path="/items"
render={routeProps => (
<Layout>
<Home
showDialog={showDialog}
openDialog={openDialog}
hideDialog={hideDialog}
{...routeProps}
/>
{showDialog && (
<Dialog
hideDialog={hideDialog}
/>
)}
</Layout>
)}
/>
<Route
path="/items/:Id/books/:bookId"
render={routeProps => (
<Layout>
<Books
openDialog={openDialog}
{...routeProps}
/>
{showDialog && (
<Dialog
hideDialog={hideDialog}
/>
)}
</Layout>
)}
</>
)
function Home ({openDialog}: Props) {
return (
<button Onclick={openDialog}>AddItem</Button>
)
}
function Books ({openDialog}: Props){
return (
<button onClick={openDialog}>AddBooks</Button>
)
}
function MessageDialog({hideDialog}: Props) {
return (
<button onClick={hideDialog}>hide</button>
)
}
Now the question is as you see i am rendering MessageDialog in two places based on showDialog value. if users clicks additems button the dialog is displayed and when user to navigates to other view and clicks addbooks button the dialog is displayed.
somehow i feel this is not the right approach or something is missing...
How can i create a global dialog component that is accessible anywhere from my app or using toastify or some better approach. could someone help me with this. thanks.
I think your code is pretty good, but I can think of two minor things that could potentially improve it.
Firstly, you have some duplicate code in your main component. You should be able to move the Dialog outside of the routes. Like so:
return (<>
{showDialog && (
<Dialog
hideDialog={hideDialog}
/>
)}
<Route ... />
<Route ... />
</>)
This will render your dialog no matter which route is matched.
Secondly, instead of passing openDialog and hideDialog callbacks as props, you could create a React context. This is optional, and dependning on the case this might not be desired. A React context is slightly more complex than just a callback, so it adds complexity to your code. The benefit is that the callbacks doesn't need to be passed down through the props of every child component, which makes the component structure cleaner if you have a large component tree.
To create a React context for this use case, you could do the following:
// Create a context with a default value of false
let DialogContext = React.createContext()
function MainComponent () {
...
return (<DialogContext.Provider value={{ setDialogOpen: (open) => setShowDialog(open) }}>
{showDialog && (
<Dialog />
)}
<Route ... />
<Route ... />
</ DialogContext.Provider>)
}
function Home ({openDialog}: Props) {
let dialogContext= useContext(DialogContext)
return (
<button onclick={() => dialogContext.setDialogOpen(true)}>AddItem</Button>
)
}
function Books ({openDialog}: Props){
let contextValue = useContext(DialogContext)
return (
<button onClick={() => dialogContext.setDialogOpen(true)}>AddBooks</Button>
)
}
function MessageDialog({hideDialog}: Props) {
let dialogContext= useContext(DialogContext)
return (
<button onClick={() => dialogContext.setDialogOpen(false)}>hide</button>
)
}

How to fix redirection problems in a react-material menu

With my menu I encounter different problem.
For starters, in the first RETURN, I have a TREEITEM with a LISTITEM and a LISTITETEXT.
I put an OnClick in the LISTITETEXT so that if the id of my menu is equal to a value I authorize a redirection.
However, the redirection reloads the page and this is not the purpose of my menu when I use react.
Second, I have my other RETURN which contains my submenu.
it is displayed correctly, when I click on the TREEITEM, I am redirected to the right page.
However, I have the error in the console:
Warning: You tried to redirect to the same route you're currently on:
"/extranetV1/prospect"
{stoMenu && (
<TreeView
style={layout.menu}
defaultCollapseIcon={<ArrowDropDownIcon />}
defaultExpandIcon={<ArrowRightIcon />}
>
{stoMenu.root.children.map(menu => {
return (
<TreeItem
key={menu.nodeId}
nodeId={menu.nodeId}
label={
<ListItem style={layout.menuListItem} className={menu.iconCls}>
<ListItemText style={layout.menuText} primary={menu.text} onClick={() => {
if (menu.id === '/accueil') {
window.location.assign(menu.id);
}
}} />
</ListItem>
}
>
{menu.children.map(child => {
return (
<TreeItem
key={child.nodeId}
nodeId={child.nodeId}
label={child.text}
>
<Redirect to={child.id}/>
</TreeItem>
);
})}
</TreeItem>
);
})}
</TreeView>
)}
For both scenarios you use redirection in react wrong.
You need to use react router for redirection inside react app and instead of window.location.assign(menu.id) it will be props.history.push(menu.id).
I see in the second one you use Redirect component. The problem is that you trigger redirect each time in the loop. You should set some state instead and trigger render with condition earlier in the code.
const MyComponent = (props) => {
const [state, setState] = useState({ pathToRedirect: null });
const handleRedirect = (to) => {
setState({ pathToRedirect: to});
}
render () {
if (state.pathToRedirect) {
return <Redirect to={state.pathToRedirect} />;
}
//render list with handleRedirect onClick
return (...);
}
To correct my problem of reloading the page, I integrated this:
<TreeItem
key={menu.nodeId}
nodeId={menu.nodeId}
label={
<ListItem style={layout.menuListItem} className={menu.iconCls}>
<ListItemText style={layout.menuText} primary={menu.text} onClick={() => {
if (menu.id === '/accueil') {
this.props.history.push(menu.id);
}
}} />
</ListItem>
}
>
I removed the REDIRECT by this in my sub menu :
<TreeItem
key={child.nodeId}
nodeId={child.nodeId}
label={child.text}
onClick={() => {
if (child.id) {
this.props.history.push(child.id);
}
}}
/>

material ui dialog automatically closes on pressing tab key

I have a react project and am using material-ui v3. I have an appBar which contains a menu with some menuItems, upon clicking the menuItem I'm opening a Dialog which contains a form, now everything seems good until I fill the first input box and press tab to switch to another and as soon as I press tab the dialog automatically closes.
Below are relevant code snippets.
header.js
<header>
<AppBar>
<Toolbar>
<Typography variant="title" color="inherit" className={classes.flex} component={Link} to='/'>
{appName}
</Typography>
<Avatar className={classes.orangeAvatar}>
<Button
color="primary"
aria-owns={anchorEl ? 'simple-menu' : null}
aria-haspopup="true"
onClick={this.handleClick}
>
{user && user.username[0] || "-"}
</Button>
</Avatar>
<Menu
id="simple-menu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={this.handleClose}
>
<ChangePassword
{...this.props}
>
{({ onClick }) => {
return (
<MenuItem onClick={onClick}>
Change password
</MenuItem>
);
}}
</ChangePassword>
<MenuItem onClick={async e => {
this.handleClose(e);
await window.localStorage.clear();
client.resetStore();
window.location.href = "/";
}}
>
<InputIcon className={classes.icon} /> Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
</header>
ChangePassword.js
class ChangePassword extends React.PureComponent {
state = {
open: false,
};
handleClose = () => {
this.setState({ open: false });
};
handleOpen = () => {
this.setState({ open: true });
};
render() {
const { open } = this.state;
const {
classes,
history,
negativeHandler = e => this.handleClose(),
positiveHandler = e => null,
postMutation = e => null,
children
} = this.props;
const title = "Change password",
content = "Change password of this user.";
return (
<Mutation mutation={UPDATE_USER_PASSWORD}>
{(mutate, { loading, error, data }) => {
return (
<React.Fragment>
{children({ onClick: this.handleOpen })}
{
open ? (
<Dialog
fullScreen={false}
open={open}
onClose={negativeHandler}
aria-labelledby={title}
>
<Form
onSubmit={e => {
positiveHandler(mutate, e)
.then((data) => {
if (postMutation) {
postMutation(data);
this.handleClose(e);
}
else {
history.goBack()
}
})
}}
>
<DialogTitle id={title}>{title}</DialogTitle>
<DialogContent>
<DialogContentText>
{content}
</DialogContentText>
{
getFormJSX(defaults)
}
</DialogContent>
<DialogActions>
{
loading ? <CircularProgress className={classes.progress} /> : null
}
<Button onClick={negativeHandler} color="primary">Cancel</Button>
<Button size="large" type="submit" disabled={loading}>Confirm</Button>
</DialogActions>
</Form>
</Dialog>
) : null
}
</React.Fragment>
);
}}
</Mutation>
);
}}
export default withStyles(styles)(ChangePassword);
The getFormJSX(defaults) method simple generates dynamic form based upon defaults object, the return value only contains form controls and not the tag itself. Beside everything work fine on a regular form in the rest of my app except or other dialogs. This problem only occurs when the dialog is inside an menuItem which is inside a menu which is inside the appBar. Please let me know if I can provide anything thing else to support my question.

Categories

Resources