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.
Related
I am using React Admin and was trying to focus an AutocompleteInput but its not working for me. Sample code as follows
const CreateFormCustom = (props) => {
const fieldRef1 = useRef(null);
const fieldRef2 = useRef(null);
const fieldRef3 = useRef(null);
return (
<SimpleForm {...props} redirect={false} >
<ReferenceInput helperText={false} fullWidth label="Users" source="u_id" reference="v1/users">
<AutocompleteInput inputRef={fieldRef1} onSelect={() => {fieldRef2.current.focus();}} optionValue="u_id" optionText="u_name" />
</ReferenceInput>
<NumberInput inputRef={fieldRef2} source="t_qty" label="Quantity" helperText={false} onKeyDown={(e)=>{if(e.which==13||e.keyCode==13) fieldRef3.current.focus();}} />
<NumberInput inputRef={fieldRef3} source="t_price" label="Price" helperText={false} onKeyDown={(e)=>{if(e.which==13||e.keyCode==13) fieldRef1.current.focus();}} />
</SimpleForm>
)}
Other two fields focus working perfectly but when i am on last field and press enter it shows error that Uncaught TypeError: Cannot read property 'focus' of null
The inputRef parameter is used inside the AutocompleteInput component and the passed parameter is ignored:
https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/input/AutocompleteInput.tsx#L465
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.
I wanted to change the variant of TextInput using material UI. The default variant is Standard and I want to change that to outlined but not able to do so. Followed documentation for material-ui Material-ui documentation
Below is my code snippet
<TabbedForm>
<FormTab label="INFO">
{/* <TextInput disabled label="" source="id" type="hidden"/> */}
<TextInput label="Name" source="name" variant="outlined"/>
<TextInput source="shortdesc" />
</FormTab>
</TabbedForm>
You need to pass in variant="standard" to the react-admin <TextInput> component. The issue is that the <Filter> and <Create> pages, etc, automatically pass in a bunch of props, like record and basePath, which includes variant: undefined for some reason. So if you just write <TextInput variant="standard" ... />, your prop will get overwritten. And then when the TextInput component passes its props to the ResettableTextField component, the now undefined variant prop gets defaulted to "filled"...
So, you just need to extract the TextInput component out, so that your variant prop comes last in the props order:
export const TextInput = props => <RaTextInput {...props} variant="standard" />
Personally, I've abstracted this all out into a HOC, because this is what you have to do for all the Inputs that use TextFields:
import React from 'react'
import {
TextInput as RaTextInput,
NumberInput as RaNumberInput,
SelectInput as RaSelectInput,
DateInput as RaDateInput,
DateTimeInput as RaDateTimeInput,
NullableBooleanInput as RaNullableBooleanInput,
AutocompleteInput as RaAutocompleteInput,
} from 'react-admin'
const standardize = Component => props => <Component {...props} variant="standard" />
export const TextInput = standardize(RaTextInput)
export const NumberInput = standardize(RaNumberInput)
export const SelectInput = standardize(RaSelectInput)
export const DateInput = standardize(RaDateInput)
export const DateTimeInput = standardize(RaDateTimeInput)
export const NullableBooleanInput = standardize(RaNullableBooleanInput)
export const AutocompleteInput = standardize(RaAutocompleteInput)
Check my code
<TabbedForm>
<FormTab label="INFO">
{/* <TextInput disabled label="" source="id" type="hidden"/> */}
<TextField label="Name" source="name" variant="outlined"/>
<TextField source="shortdesc" />
</FormTab>
</TabbedForm>
check my fork
React-admin has fixed this.
You can now use the variant="outlined | standard | filled" prop on the component enclosing the input.
Ex: SimpleForm, Create, Filter, etc.
The Git resolution
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}"
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>
// ...