Is it possible to use material-ui button navigation with react-router? - reactjs

I have a web app that I'v designed with material-UI and as you can see below I'm using Button navigation for navigating through my basic landing page components.
<div className="footer">
<BottomNavigation value={value} onChange={this.handleChange} className={classes.root}>
<BottomNavigationAction label="signal" value="signal" icon={<ShowChart />} className={classes.content}/>
<BottomNavigationAction label="hotlist" value="hotlist" icon={<HotList />} className={classes.content}/>
<BottomNavigationAction label="analyze" value="analyze" icon={<PieChart />} className={classes.content}/>
<BottomNavigationAction label="learn" value="learn" icon={<LibraryBooks/>} className={classes.content}/>
<BottomNavigationAction label="dashboard" value="dashboard" icon={<PermIdentity/>} className={classes.content}/>
</BottomNavigation>
</div>
I've tried to use React-Router with these predefiend navigation component but that didn't work, is there any possible way to use Router with Button navigation of material-UI?
Button navigation article in material-UI
ButtonNavigation API

Yes, it's possible. You need to use the component prop:
import { Link } from 'react-router-dom';
import BottomNavigation from '#material-ui/core/BottomNavigation';
import BottomNavigationAction from '#material-ui/core/BottomNavigationAction';
// ....
<BottomNavigation value={value} onChange={this.handleChange}>
<BottomNavigationAction
component={Link}
to="/signal"
label="signal"
value="signal"
icon={<ShowChart />}
className={classes.content}
/>
</BottomNavigation>
(the to prop is for React Router's Link component)
This works with any Material-UI component that inherits from ButtonBase.
https://material-ui.com/api/bottom-navigation-action/
Inheritance
The properties of the ButtonBase component are also
available. You can take advantage of this behavior to target nested
components.
https://material-ui.com/api/button-base/
Props
component - The component used for the root node. Either a string to use a DOM element or a component.

Just to add on to the great answer by #thirtydot , in case the user types into the search and visits a particular webpage directly (other than default) e.g. "www.yoursite.com/tab2", instead of clicking the 2nd button, this may cause a mismatch between the site that is showing and the BottomNav Button that is focused (usually the 1st button).
Here is what I did:
I used window.location.pathname to get the current path which is '/tab2' directly.
Here is my code for my particular use case....
function BottomNavBar(){
const pathname = window.location.pathname; // in case user visits the path directly. The BottomNavBar is able to follow suit.
const [value, setValue] = React.useState(pathname);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<BottomNavigation value={value} onChange={handleChange} showLabels={true} >
<BottomNavigationAction label="home" value="/" icon={<HomeIcon />} component={Link} to='/'/>
<BottomNavigationAction label="resources" value="/resources" icon={<ResourcesIcon /> } component={Link} to='/resources'/>
<BottomNavigationAction label="Q&A" value="/qna" icon={<QnAIcon />} component={Link} to='/qna'/>
<BottomNavigationAction label="profile" value="/profile" icon={<ProfileIcon />} component={Link} to='/profile'/>
</BottomNavigation>
);
}

in new versions theres this property "LinkComponent" which lets you link directly to a component that renders the page you want, very similar to previus answers:
import { Link } from 'react-router-dom';
import BottomNavigation from '#material-ui/core/BottomNavigation';
import BottomNavigationAction from '#material-ui/core/BottomNavigationAction';
// ....
<div className="footer">
<BottomNavigation value={value} onChange={this.handleChange} className={classes.root}>
<BottomNavigationAction label="signal" value="signal" icon={<ShowChart />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
<BottomNavigationAction label="hotlist" value="hotlist" icon={<HotList />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
<BottomNavigationAction label="analyze" value="analyze" icon={<PieChart />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
<BottomNavigationAction label="learn" value="learn" icon={<LibraryBooks/>} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
<BottomNavigationAction label="dashboard" value="dashboard" icon={<PermIdentity/>} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
</BottomNavigation>
</div>
// ...

Related

How to reset useState everytime I change my page?

I'm working on a Hamburger Navbar
here is my page look like:
the issues is whenever I clicked to another route but the navbar still appear on right side. I want to make it whenever I go to another route it will disappear.
Here is my code:
const App = (props) => {
const [ menuOpen, setMenuOpen ] = useState(false);
<HamburgerNav>
<HamburgerNavContainer>
<LogoLinkStyled to="/">
<LogoNav src="https://thebeuter.com/wp-content/uploads/2020/04/logo-black.png" />
</LogoLinkStyled>
<HamburgerUtilities>
<HamburgerUlityItem>
<Icon className="fal fa-search fa-rotate-90" onClick={openModalHandler} />
</HamburgerUlityItem>
<HamburgerUlityItem>
<Link to="/cart" style={{ color: 'black', textDecoration: 'none' }}>
<Icon className="fal fa-shopping-bag" />
<CartNumb>({props.basketProps.basketNumbers})</CartNumb>
</Link>
</HamburgerUlityItem>
<HamburgerUlityItem>
<HamburgerLine onClick={() => setMenuOpen(!menuOpen)} />
</HamburgerUlityItem>
</HamburgerUtilities>
</HamburgerNavContainer>
</HamburgerNav>
How can I fix this problem? Really appreciate it.!!!
Github project: https://github.com/nathannewyen/the-beuter
update Router code:
Here is my Router for all routes in navbar
<Router>
<ContactForm path="/contact" />
<SizeChart path="/size-chart" />
<ShippingAndReturn path="/shipping-return" />
<PrivacyAndPolicy path="/privacy-policy" />
<AboutUs path="/about-us" />
<ShopAllProducts path="/" />
<NewArrival path="/shop/new-arrival" />
<Tops path="/product-category/top" />
<Bottoms path="/product-category/bottom" />
<Product path="/product/:title_url" />
<SearchInfo path="/search/:title" searchTerm={searchTerm} title="Profile" />
<Cart path="/cart" />
<Checkout path="/checkout" />
</Router>
You need to add onClick to the "route" component that is not closing it and do something like this:
onClick={() => { setMenuOpen(prevState => {return !prevState}) }}
If for example you want it to close when you click on "T-Shirts", then "T-Shirts" must also have that onClick.
If you already have onClicks on these components with another function, you can just add multiple functions inside the anonymous function like this:
onClick={() => {
YourOtherFunction();
setMenuOpen(prevState => {return !prevState});
}
If your components are not in the App.js you need to somehow pass the onClick down too them.
Since its a state you wont be able to pass down the setMenuOpen itself, you need a wrapper function. So first create the wrapper:
const setMenuOpenWrapper = () => {
setMenuOpen(prevState => return { !prevState });
}
Then pass it down to the childrens like:
and then inside your ContactForm on the link to the contact form add the onClick:
...onClick={() => { closeMenuFunction(); }}
Ok I just checked your code, you need to pass down the function to the Sidenav component.
So in your App.js first create the wrapper function as I explained above
After that again in App.js on line 316 where you have <SideNav menuOpen={menuOpen} /> change it to <SideNav menuOpen={menuOpen} closeMenuFunction={setMenuOpenWrapper}/>
Then in your Sidenav.jsx on all of your menu items add an onclick:
onClick={props.closeMenuFunction}
And then it should work.

How to hide multiple fields in react-admin ShowView?

I am trying to hide a set of fields based on the value of another field but the following will not display the conditional fields ever:
export const ServiceShow = (props) => (
<ShowController {...props}>
{controllerProps =>
<ShowView component="div" {...props} {...controllerProps}>
<TabbedShowLayout>
<Tab label="General">
{controllerProps.record && controllerProps.record.maintenance &&
controllerProps.record.maintenance.active &&
<>
<Alert severity="warning">Maintenance period active</Alert>
<DateField label="Maintenance Start" src="maintenance.start" />
<DateField label="Maintenance End" srvc="maintenance.end" />
<TextField label="Maintenance Message" source="maintenance.msg" />
</>
}
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
);
The <Alert> is displayed just fine, but the Field components are not. I'm very new to React so probably a simple thing.
Note:If I put a single <TextField> as the conditional output then it will work but anything inside a React.Fragment or <div> for example, it doesn't work.
The reason why Alert shows up and Fields not is because Fields require addtional props passed by react-admin direct parent, in that case, the Tab. <> should pass such props too, but looks like it's not. And thats why a single <TextField> as child renders correctly
You can create a component that pass the props downstream to childs.
export const ServiceShow = (props) => (
<ShowController {...props}>
{controllerProps =>
<ShowView component="div" {...props} {...controllerProps}>
<TabbedShowLayout>
<Tab label="General">
<Maintenance/>
</Tab>
</TabbedShowLayout>
</ShowView>
}
</ShowController>
);
const Maintenance = props => (
{props.record && props.record.maintenance && props.record.maintenance.active &&
<>
<Alert {...props} severity="warning">Maintenance period active</Alert>
<DateField {...props} label="Maintenance Start" src="maintenance.start" />
<DateField {...props} label="Maintenance End" srvc="maintenance.end" />
<TextField {...props}label="Maintenance Message" source="maintenance.msg" />
</>
}
)

No impact on URL with Material-UI BottomNavigation

I am trying to create a Bottom Navigation bar using material-ui (link:https://material-ui.com/components/bottom-navigation/).
Unfortunately, when I created the component, clicking on each tap did not affect my URL.
Initially, I was using the Link component from React, which allowed me to route between various components. However, as I integrate the Link component into the BottomNavigation component, the style changes and is not working properly anymore.
Here's my current code (without the Link component):
function NavigationAuth() {
const [value, setValue] = React.useState("/");
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<BottomNavigation
value={value}
onChange={handleChange}
showLabels
>
<BottomNavigationAction label="Home" value="/" icon={<HomeIcon />} />
<BottomNavigationAction label="Progress" value="/home" icon={<TimelineIcon />} />
<BottomNavigationAction label="Vote" value="/overview" icon={<ThumbsUpDownIcon />} />
<BottomNavigationAction label="Account" value="/account" icon={<AccountCircleIcon />} />
</BottomNavigation>
);
}
Does anyone have an idea how I can actually change the URL (while using the BottomNavigation component) as a normal Link component would do?
Many thanks in advance!
You can import {useHistory} from react-router-dom and use it to change the URL:
function NavigationAuth() {
const [value, setValue] = React.useState("");
const history = useHistory();
const handleChange = (event, newValue) => {
history.push(`/${newValue}`);
setValue(newValue);
};
return (
<BottomNavigation
value={value}
onChange={handleChange}
showLabels
>
<BottomNavigationAction label="Home" value="" icon={<HomeIcon />} />
<BottomNavigationAction label="Progress" value="progress" icon={<TimelineIcon />} />
<BottomNavigationAction label="Vote" value="overview" icon={<ThumbsUpDownIcon />} />
<BottomNavigationAction label="Account" value="account" icon={<AccountCircleIcon />} />
</BottomNavigation>
);
}
You need both react-router and material-ui to accomplish what you're describing. Material-ui is a UI library and has no intention of providing functionality like routing, only the UI to control routing however you see fit.
Instead of using Link, and assuming this component is wrapped by BrowserRouter at a higher level, change the URL in your handleChange function like this:
const handleChange = (event, newValue) => {
props.history.push(newValue);
};
history is a prop injected by react-router that lets you programmatically update the URL by calling push.
The other way to do this would be the useHistory hook instead of passing it as a prop.

No translation for MenuItemLink's primaryText in react-admin

I'm using a custom user menu and the primarytext is not translated as expected.
No problems with the others components.
const MyUserMenu = props =>
<UserMenu {...props}>
<MenuItemLink
to="/configuration"
primaryText="labels.configuration"
leftIcon={<SettingsIcon />}
/>
</UserMenu>
You'll have to explicitly translate it as the MenuItemLink component is not currently responsible for translations (might be a good feature request btw).
import { translate, UserMenu, MenuItemLink, translate } from 'react-admin';
const MyUserMenu = translate(({ translate, ...props }) =>
<UserMenu {...props}>
<MenuItemLink
to="/configuration"
primaryText={translate("labels.configuration")}
leftIcon={<SettingsIcon />}
/>
</UserMenu>
it should be wrapped with curly brackets
"{labels.configuration}"

How to add search bar in AppBar of material-ui?

I want to implement Search bar in the center of App bar of material-ui. I have tried all possible ways and I have referred this code snippet , but can't find a solution for it.
My code snippet is
<div>
<MuiThemeProvider muiTheme={muiTheme} class="navbar">
<AppBar
title='Module Name'
onTitleClick={handleClick}
iconElementRight={<FlatButton label='LogOut' />}
onClick = {handleclick}
/>
</MuiThemeProvider>
</div>
It will be helpful if I get any solution for it.
You can use children property to add any node in AppBar, like this:
<AppBar
title="Title"
children= {
<input />
}
/>
Use styling on input field, check the working codesandbox.
you can add a ToolBar contains a Textfield
you can check documentation ,this is a Demo
Using only Material UI
<AppBar>
<Toolbar>
<Input
type="search"
/>
</Toolbar>
</AppBar>
You can check the docs here.
Installing another framework.
npm i material-ui-search-bar
A basic code snippet can be found on the main page.
import SearchBar from "material-ui-search-bar";
// *snip*
return (
<SearchBar
value={this.state.value}
onChange={(newValue) => this.setState({ value: newValue })}
onRequestSearch={() => doSomethingWith(this.state.value)}
/>
);
You can check the docs here.
Try this
<AppBar>
<Toolbar>
<InputBase placeholder="Search for products, brands and more" />
</Toolbar>
</AppBar>
Pass a prop in the AppBar component
<AppBar
title="Title"
showSearch= {
<Toolbar>
<InputBase placeholder="Search" />
</Toolbar>
}
/>
You can handle AppBar component based on customName prop like if you're passing this prop then it should show Search else not.

Resources