fortawesome/react-fontawesome package change icon onclick - reactjs

I have the following icon in my code:
<FontAwesomeIcon id="star" onClick={this.handleClick} icon={hollowstar} size="lg" />
I need the icon to change from hollowstar to solidstar onclick. How can this be accomplished?

You can do something like this:
import { faStar as fasFaStar } from '#fortawesome/free-solid-svg-icons';
import { faStar as farFaStar } from '#fortawesome/free-regular-svg-icons';
// ...
const [star, setStar] = useState(farFaStar);
// ...
<FontAwesomeIcon
onClick={() => {
setStar(fasFaStar);
}}
icon={star}
// Other props...
/>
So in the code we import the same star icon with different styles like described in the documentation here: https://github.com/FortAwesome/react-fontawesome#how-do-i-import-the-same-icon-from-two-different-styles.
Since the icon is just an object you can save it to the state and update the state to the other icon inside an onClick function.
For clarity, I've used a functional component here.

Related

Im building a React App that requires a pdf to download, in the event the (materialUI) download button is clicked, how can I add that functionality?

the profile component contains the following code:
<div className="button_container" style={{display:'flex'}}>
<DownloadButton text={'PDF'} icon={<GetAppIcon />} />
</div>
the button component contains the following code:
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button onClick={() => { }} className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
**I've added an onClick event but am having difficulty figuring the simplest way to trigger the file to download, once the button is clicked **
Any comments are appreciated
Turn your button into a link and provide the path to your pdf file
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button component="a" href="PATH_TO_YOUR_PDF_FILE" className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
The simplest way to achieve this is to use an HTML anchor and style it like a button.
Download PDF
With material core buttons you need to add the href prop and it will use an anchor tag instead of a button tag.
<Button href="/path/to/file.pdf">Download PDF</Button>
Your download button would look like
const DownloadButton = ({text, icon}) => {
const endIcon = icon ? (<div className="btn_icon_container" >{icon}</div>) : null;
return (
<Button href="file.pdf" className="custom_btn" endIcon={endIcon}>
<span className="btn_textw">{text}</span>
</Button>
)
}

Component to call all material-ui Icon in React

I want to implement a component which calls the corresponding icon from material-ui. I've made it work when manually calling it.
import MenuIcon from '#material-ui/icons/Menu';
export const Icon = (props) => {
return (
<div>
<MenuIcon/>
</div>
)
}
The problem is I don't know how to change the import for all icons.
I want to call this component the following way:
<Icon icon="MenuIcon" className="someClass" />
<Icon icon="LocationOn" className="someClass" />
<Icon icon="Notifications" className="OthersomeClass" />
I can't figure out how to import all icons and how to change my Icon component to work for any icon from the material-ui package.
Something like this...
import React from 'react';
import * as IconList from '#material-ui/icons/Menu'; //error
export const Icon = (props) => {
const {icon, className} = props;
return (
<`${icon}` className={className} /> {//error}
)
}
Any ideas?
You should be able to import all the icons using named imports or the star imports (* as).
Star imports should look like this
import * as Icons from "#material-ui/icons";
<Icon icon={Icons.Menu} className="someClass" />
<Icon icon={Icons.AccessAlarmIcon} className="someClass" />
Named imports should look like this
import { Menu, AccessAlarmIcon } from "#material-ui/icons";
<Icon icon={Menu} className="someClass" />
<Icon icon={AccessAlarmIcon} className="someClass" />
You can also refactor your Icon component to utilize the React children prop, that way you can better compose each icon on the Icon component.
So it should look something like this
import React from 'react';
export const Icon = ({ children }) => {
return (
<>{children}</>
)
}
Then you can use it like this
<Icon>
<Menu className="someClass" />
</Icon>
<Icon>
<AccessAlarmIcon className="someClass" />
</Icon>
PS:
Your star imports were from '#material-ui/icons/Menu' as opposed to just '#material-ui/icons' and that caused an error

antd modal on modal click not opening

I have an antd modal as shown in the below code, Now when I select Create Manual and click Next, I want to close this modal and open another Modal2 but another modal is not getting opened after clicking next.
Here is my code. ( Codesandbox live demo - link )
Please suggest a workaround to get his second modal generated. Thanks
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Modal, Button, Radio } from "antd";
const App = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectRadio, setselectRadio] = useState("preselect");
const showModal = () => {
setIsModalVisible(true);
};
const select = (e) => {
// you can save the value in here
setselectRadio(e.target.value);
console.log(e.target.value);
};
function modalclick() {
if (selectRadio === "preselect") {
alert("pre-select");
} else {
//---------------> UNABLE TO OPEN ANOTHER MODAL HERE <-------------------------------------
<Modal title="Create Test Suite" visible={isModalVisible}>
MODAL 2 COMES HERE
</Modal>;
alert("manual");
}
}
return (
<>
<Button type="primary" style={{ float: "right" }} onClick={showModal}>
Create Test Suite
</Button>
<Modal
title="Create Test Suite"
visible={isModalVisible}
footer={[
<Button key="cancel" onClick={() => setIsModalVisible(false)}>
Cancel
</Button>,
<Button type="primary" key="next" onClick={modalclick}>
Next
</Button>
]}
>
<Radio.Group
defaultValue="preselect"
buttonStyle="solid"
onChange={(e) => {
select(e);
}}
>
<Radio value="preselect">Create from Preselect</Radio>
<Radio value="manual">Create Manual</Radio>
</Radio.Group>
</Modal>
</>
);
};
ReactDOM.render(<App />, document.getElementById("container"));
To show the modal 2 you can use a useState hook or a useRef hook. In both methods, you need first to put this modal 2 in the return of your "App".
useState way: Just use a state to control the visibility, like how you do in modal 1, simple.
useRef way: This is a little more complex. You will need to use a useImperativeHandle inside the modal component, and create a function (inside too) to control the visibiliity. So, in your page, you can just call the function that is inside the component, to show the modal. Using this method, the logic about the state control of visibility leaves the page and goes into the component.
Modal2 is not visible because is out of the return of App function. Put Modal 2 inside return and try again.

How to ignore Material UI theme styling for component?

My button component (that is also a material UI component) already has the style I want, but when I surround it with the Link component, which is a react-dom-router component, it overrides the style of my button.
How to ignore the default style of Link?
<AppBar>
<Toolbar>
<Link to="/some-link">
<Button>
My Button
</Button>
</Link>
</Toolbar>
</AppBar>
Nesting a Link (<a>) inside a Button (<button>), and viceversa, is not valid HTML. I would recommend you either remove the Button or you use react-router and add props.history.push("/some-link") to your Button onClick handler. Like this:
<Button onClick={() => history.push("/some-link")}>My Button</Button>
Take a look at this sandbox I made. Let me know if it helps.
Instead of nesting a button inside a Link (which is weird because they are both clickable elements) just use the Button with an onClick handler where you can manually trigger the route change.
See also React-router: How to manually invoke Link?
Here's the example given on the material ui site. You probably don't need the router part though.
https://material-ui.com/components/buttons/#ButtonRouter.js
import React from 'react';
import { MemoryRouter as Router } from 'react-router';
import { Link } from 'react-router-dom';
import Button from '#material-ui/core/Button';
// The usage of React.forwardRef will no longer be required for react-router-dom v6.
// see https://github.com/ReactTraining/react-router/issues/6056
const AdapterLink = React.forwardRef((props, ref) => <Link innerRef={ref} {...props} />);
const CollisionLink = React.forwardRef((props, ref) => (
<Link innerRef={ref} to="/getting-started/installation/" {...props} />
));
export default function ButtonRouter() {
return (
<Router>
<Button color="primary" component={AdapterLink} to="/">
Simple case
</Button>
<Button component={CollisionLink}>Avoids props collision</Button>
</Router>
);
}

How to reuse a Custom Material-ui button inside a react-app?

I'm developing my first React app. I've imported a Material-ui button and I've customized it.
Now I want to reuse this custom button in several components of my app. I want a different text for each time I use this custom button.
Where do I need to write this specific text for each button?
My button is visible when I import it in other components, but I can't see the text I wrote inside the button component. The button stays empty.
My custom button component : MyButton:
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
button: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20
}
});
function MyButton(props) {
const { classes } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> </b>
</Button>
);
}
export default withStyles(styles)(MyButton);
The other component where I import MyButton component : Home :
import React from "react";
import "../App.css";
import MyButton from "./Button";
function Header() {
return (
<header className="Header">
{/* background image in css file */}
<h1>Welcome </h1>
<h3> description...</h3>
<MyButton>Play now</MyButton>
</header>
);
}
export default Header;
I expect the button to show "Play now" (expected output) but for now it stays empty (actual output).
Also, I've found another solution that offers the possibility to write directly the text inside each button (children of MyButton), and customize it if needed.
Pass "children" keyword as "props" to MyButton component :
function MyButton(props) {
const { classes, children } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b>{children}</b>
</Button>
);
}
Then write the text of your button inside the button as you will do in html :
<MyButton> Play now </MyButton>
You will get the most flexibility from your custom Button if you pass all of the props along to the wrapped Button. This will automatically take care of children and classes so long as you use class keys in your styles object that match the CSS classes supported for the wrapped component.
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
root: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20,
fontWeight: "bold"
}
});
function CustomButton(props) {
return <Button variant="contained" color="primary" {...props} />;
}
export default withStyles(styles)(CustomButton);
Notice in the sandbox example, that this allows you to still leverage other Button features like disabled, specify additional styles, or override some properties specified in CustomButton.
If you have a scenario where you need to handle children explicitly (in my example above I used fontWeight CSS instead of the <b> tag), you can use the following syntax to still pass all the props through to the wrapped component:
function CustomButton({children, ...other}) {
return <Button variant="contained" color="primary" {...other}><b>{children}</b></Button>;
}
Pass text of button as props to your button component
<MyButton text="Play now"></MyButton>
Then inside MyButton component you can get it like
function MyButton(props) {
const { classes,text } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> {text} </b>
</Button>
);
}

Resources