dynamic ionic icon with react typescript - reactjs

I want to make my IonIcons dynamic so they are reusable. But i need to set it in {} I dont know how i do this with a .map() element.
import React from "react";
import { IonIcon, IonLabel } from "#ionic/react";
import styles from "./quickOptions.module.css";
import { alarmOutline, personOutline, cartOutline } from "ionicons/icons";
export default function quichOptions() {
const quickOptions = [
{ title: "Jouw consulent", icon: { personOutline } },
{ title: "Jouw afspraken", icon: { alarmOutline } },
{ title: "Jouw bestellingen", icon: { cartOutline } },
];
return (
<div className={styles.mainContainer}>
{quickOptions?.map((element: any) => {
return (
<div key={element.title} className={styles.btnContainer}>
<IonLabel>{element.title}</IonLabel>
<IonIcon icon={element.icon} size="large" /> //here
</div>
);
})}
</div>
);
}
Element.icon does not give the output of {personOutline} for example does anybody know how to fix this??

you can check console.log(typeof element.icon)
const quickOptions = [
{ title: "Jouw consulent", icon: 'personOutline' },
];
<IonIcon icon={element.icon} size="large" />
if the icon type here is {string}, that's why it doesn't work
try it in quickOptions , icon: personOutline or icon: 'personOutline'

Related

How can I do to choose an option from a select when I click on a button using React?

I would like to choose the option "Apple" from the select when I click on the "Apple" button using React
import React from "react";
import { render } from "react-dom";
import ReactDOM from "react-dom";
import Select from "react-select";
import "react-select/dist/react-select.css";
class ReactSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
itemtitle: "",
multi: true,
multiValue: [],
options: [
{ value: "Color", label: "Yellow" },
{ value: "Fruit", label: "Apple" },
{ value: "Tool", label: "Spanner" }
]
};
}
onTitleChange(e, value) {
this.setState({ [e.target.name]: e.target.value });
this.setState({ multiValue: e.target.value });
}
handleOnChange(value) {
this.setState({ multiValue: value });
}
render() {
return (
<div>
<Select.Creatable
multi={this.state.multi}
options={this.state.options}
onChange={this.handleOnChange.bind(this)}
value={this.state.multiValue}
showNewOptionAtTop={false}
/>
<button>Apple</button>
</div>
);
}
}
ReactDOM.render(<ReactSelect />, document.body);
The full code of my project is there :
The full code
How can I do that ? Thank you very much !
You can update the select field value when you click the button something like this.
handleOnClick = () => {
this.setState({ multiValue: [{ value: "Fruit", label: "Apple" }] });
};
render() {
return (
<div>
<Select.Creatable
multi={this.state.multi}
options={this.state.options}
onChange={this.handleOnChange.bind(this)}
value={this.state.multiValue}
showNewOptionAtTop={false}
/>
<button
onClick={() => {
this.handleOnClick();
}}
>
Apples
</button>
</div>
);
}
Attached a sandbox link also.

How do I make each button drop show the video that is clicked? ReactJS

I am passing through props to my Buttons.jsx file. Each button would drop down a video. My problem is that when I click one button, all of the videos appear. I want it so that only that certain video that was clicked would show.
here is the link to repo
https://noahfarinas.github.io/stretching/
Thanks in advance!
Buttons.jsx
import { useState } from "react";
import ReactPlayer from "react-player";
export const Buttons = (props) => {
const { content } = props;
const [showVideo,setShowVideo] = useState(false);
const handleOnClick = () => setShowVideo(true);
return (
<div className="buttonContainer">
{content.map((item) => (
<div className="buttonSpace">
<button id="btn" onClick={handleOnClick}>{item.title}</button>
{showVideo ? <ReactPlayer url={item.embed} /> : null}
</div>
))}
</div>
);
};
export default Buttons;
**App.js**
import "./App.css";
import Search from "./Search";
import TitleView from "./TitleView";
import Buttons from "./Buttons";
function App() {
const TITLE = "Stretches";
const DATA = [
{
area: "upper-back",
video: "https://www.youtube.com/watch?v=bTn89EBKJdM",
},
{
area: "mid-back",
video: "https://www.youtube.com/watch?v=VnDuWC40egg",
},
{
area: "lower-back",
video: "https://www.youtube.com/watch?v=N-xqKx8oshs",
},
{
area: "hips",
video: "https://www.youtube.com/watch?v=nLuvQCTPrcY",
},
{
area: "calves",
video: "https://www.youtube.com/watch?v=37GHTaoknfw",
},
{
area: "chest",
video: "https://www.youtube.com/watch?v=NePr1XKRTLU",
},
{
area: "glute",
video: "https://www.youtube.com/watch?v=eRCpceBhcm0",
},
{
area: "foot",
video: "https://www.youtube.com/watch?v=AXSj_5pBAKw",
},
{
area: "forearm",
video: "https://www.youtube.com/watch?v=Ayhu7TzNGSQ",
},
{
area: "it band",
video: "https://www.youtube.com/watch?v=i6Psvd81Hyc",
},
{
area: "hamstring",
video: "https://www.youtube.com/watch?v=pJUwEBgxWoE",
},
{
area: "tricep",
video: "https://www.youtube.com/watch?v=SaZK9vlSmHI",
},
{
area: "lat",
video: "https://www.youtube.com/watch?v=6V5tSn9oEJg",
},
];
const BUTTONDATA = [
{
title: "back",
embed: "https://www.youtube.com/watch?v=buF1v8aiTvM",
},
{
title: "legs",
embed: "https://www.youtube.com/watch?v=UIRTPXj1Q1U",
},
{
title: "upper-body",
embed: "https://www.youtube.com/watch?v=Kpd9ik93Sxk",
},
{
title: "hips",
embed: "https://www.youtube.com/watch?v=j42sLnoMkrA",
},
];
return (
<div className="App">
<TitleView headline={TITLE} />
<Search placeholder="What hurts..." data={DATA} />
<Buttons content={BUTTONDATA} />
</div>
);
}
export default App;
The problem can be solved in two ways. One way is to have a map in app.js on the BUTTONDATA and render separate component for each item of the array. In this way each Button Component will have its own state and will show only its own contents upon button click.
The other way is to have a boolean property for each of array item in the BUTTONDATA. and then you can modify your component in the following way:
Button.js
import { useEffect, useState } from "react";
import ReactPlayer from "react-player";
const Buttons = (props) => {
const { content } = props;
const [visibilityChanged, setVisibiltyChanged] = useState(false);
useEffect(() => {}, [visibilityChanged]);
const handleOnClick = (index) => () => {
content[index].isVisible = !content[index].isVisible;
setVisibiltyChanged(!visibilityChanged);
};
return (
<div className="buttonContainer">
{content.map((item, index) => (
<div className="buttonSpace" key={index}>
<button id="btn" onClick={handleOnClick(index)}>
{item.title}
</button>
{item.isVisible ? <ReactPlayer url={item.embed} /> : null}
</div>
))}
</div>
);
};
export default Buttons;
and in app.js will have the following changes:
App.js
const BUTTONDATA = [
{
title: "back",
embed: "https://www.youtube.com/watch?v=buF1v8aiTvM",
isVisible: false
},
{
title: "legs",
embed: "https://www.youtube.com/watch?v=UIRTPXj1Q1U",
isVisible: false
},
{
title: "upper-body",
embed: "https://www.youtube.com/watch?v=Kpd9ik93Sxk",
isVisible: false
},
{
title: "hips",
embed: "https://www.youtube.com/watch?v=j42sLnoMkrA",
isVisible: false
}
];
Here is the code sandbox I created to toggle videos on button click.

ReactJS: Change html/jsx element dynamically

I wanna change my JSX element tag dynamically but the remaining attributes stay the same.
Let's say I have something like this:-
import React, { useState } from 'react'
import classNames from 'classnames'
import { makeStyles } from '#material-ui/core/styles'
import DesktopWindowsIcon from '#material-ui/icons/DesktopWindows'
import DnsIcon from '#material-ui/icons/Dns'
import StorageIcon from '#material-ui/icons/Storage'
import CloudIcon from '#material-ui/icons/Cloud'
export const try = () => {
const classes = useStyles()
const [changeIconColor, setChangeIconColor] = useState('')
const icons = [
{ id: 0, icon: <DesktopWindowIcon /> },
{ id: 1, icon: <DnsIcon /> },
{ id: 2, icon: <StorageIcon /> },
{ id: 3, icon: <CloudIcon /> },
]
return (
<>
{icons.maps(icon => (
<>
{/* this will work */}
{icon.icon}
</>
))}
</>
)
}
const useStyles = makeStyles((theme) => ({
icon: {
width: 100,
height: 100,
marginBottom: 12,
},
iconMouseHover: {
color: theme.palette.secondary.main
}
}))
But what I wanna do is something like this:-
import React, { useState } from 'react'
import classNames from 'classnames'
import { makeStyles } from '#material-ui/core/styles'
import DesktopWindowsIcon from '#material-ui/icons/DesktopWindows'
import DnsIcon from '#material-ui/icons/Dns'
import StorageIcon from '#material-ui/icons/Storage'
import CloudIcon from '#material-ui/icons/Cloud'
export const try = () => {
const classes = useStyles()
const [changeIconColor, setChangeIconColor] = useState('')
const icons = [
{ id: 0, icon: <DesktopWindowsIcon key={icon.id} className={changeIconColor === icon.id ? classNames(classes.icon, classes.iconMouseHover) : classes.icon} /> },
{ id: 1, icon: <DnsIcon key={icon.id} className={changeIconColor === icon.id ? classNames(classes.icon, classes.iconMouseHover) : classes.icon} /> },
{ id: 2, icon: <StorageIcon key={icon.id} className={changeIconColor === icon.id ? classNames(classes.icon, classes.iconMouseHover) : classes.icon} /> },
{ id: 3, icon: <CloudIcon key={icon.id} className={changeIconColor === icon.id ? classNames(classes.icon, classes.iconMouseHover) : classes.icon} /> },
]
return (
<>
{icons.maps(icon => (
<>
{/* this will not work since it gave me an error saying icon is not defined in array above */}
{icon.icon}
</>
))}
</>
)
}
const useStyles = makeStyles((theme) => ({
icon: {
width: 100,
height: 100,
marginBottom: 12,
},
iconMouseHover: {
color: theme.palette.secondary.main
}
}))
Is there any ways for me to do this dynamically with React?
Something that can change the icon tag but the remaining attributes stay the same:-
// only tag name changes
<OnlyThisChange className={changeIconColor === skill._id ? classNames(classes.icon, classes.iconMouseHover) : classes.icon} />
Is this possible with react?
yes, this possible.
First of all, you don't need to write a key in the icon component. Prop key must be defined in the Fragment element(<> -> <React.Fragment key={icon.id}>).
Your example is almost correct, one mistake that you're doing is:
changeIconColor === icon.id
instead of the above example, you can hardcode your ids:
changeIconColor === 1

react-ace + flexlayout-react: Ace editor keeps resetting

I have a FlexLayout (from flexlayout-react) which contains an AceEditor (from react-ace). For testing I added a Test component as well.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import FlexLayout from 'flexlayout-react';
import AceEditor from 'react-ace';
// display an Ace editor (here with fixed size)
const Editor = () => {
return (
<AceEditor
width="200px"
height="200px"
value="foo"
/>
);
}
// an increment button, just something simple stateful
const Test = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>
{count}
</button>
</div>
);
};
// two columns for editor and test component
const model = FlexLayout.Model.fromJson({
global: {},
borders: [],
layout: {
type: 'row',
weight: 50,
children: [
{
type: 'tabset',
weight: 50,
selected: 0,
children: [
{
type: 'tab',
name: 'A',
component: 'editor',
},
],
},
{
type: 'tabset',
weight: 50,
selected: 0,
children: [
{
type: 'tab',
name: 'B',
component: 'test',
},
],
},
],
},
});
const factory = node => {
switch (node.getComponent()) {
case 'editor': {
return <Editor />;
}
case 'test': {
return <Test />;
}
default:
return null;
}
}
// display the flex layout
const Ide = () => {
return (
<FlexLayout.Layout
model={model}
factory={factory}
/>
);
};
// render everything
ReactDOM.render(
<Ide />,
document.getElementById('react-container')
);
So what's going on?
Whenever the FlexLayout state changes (focus changed, dragging the divider, changing width), the text of the Ace editor is reset to foo. In contrast, the value of Test is preserved. Without the FlexLayout, the problem goes away.
So there seems to be a curious interaction between the two components, but I'm too inexperienced with React to figure it out. How would I go about debugging this? What are common avenues of approach with such an issue? Or any concrete ideas where the error is in this specific situation?

I have a card component that I need to update to add new items

I built a card component that shows a list of user data and images with antd on nextJs. I want to build a functionality that creates a modal to input new data and image and adds it to the user interface as a new card, but I am confused on how to get my hands around it. I need assistance. Here's a link to my code!
import React from 'react';
import { Avatar, Card, Icon, List } from 'antd';
import { ICON_LIST, LIST_TEXTS, STYLES, USER_UPLOAD } from './constants';
const { AVATAR, CARD_CONTAINER, ICON, USER_LIST } = STYLES;
const { INNER, MORE, UPLOAD, VERTICAL } = LIST_TEXTS
class Home extends React.Component {
state = {
clicks: 0,
};
IncrementIconText = () => {
this.setState({ clicks: this.state.clicks + 1 });
}
render() {
const actions = ( ICON_LIST.map(({ type }) => (
<span>
<Icon key={type} type={type} onClick={this.IncrementIconText} style={ICON} />
{this.state.clicks}
</span>
)));
return (
<List
itemLayout={VERTICAL}
dataSource={USER_UPLOAD}
renderItem={item => (
<List.Item style={USER_LIST}>
<Card
actions={actions}
cover={<img alt={UPLOAD} src={item.image} />}
extra={<Icon type={MORE} />}
hoverable
title={<a><Avatar src={item.image} style={AVATAR} />{item.user}</a>}
type={INNER}
style={CARD_CONTAINER}
>
{item.story}
</Card>
</List.Item>
)}
/>
);
}
}
export default Home;
constants.js
export const ICON_LIST = [
{
key: "heart",
type: "heart",
},
{
key: "dislike",
type: "dislike",
},
{
key: "meh",
type: "meh",
},
]
export const LIST_TEXTS = {
INNER: "inner",
MORE: "more",
UPLOAD: "upload",
VERTICAL: "vertical",
};
export const STYLES = {
AVATAR: {
marginRight: 8
},
CARD_CONTAINER: {
width: "650px",
marginBottom: 50
},
ICON: {
marginRight: 8
},
USER_LIST: {
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center"
},
};
export const USER_UPLOAD = [
{
image: "http://sugarweddings.com/files/styles/width-640/public/1.%20The%20Full%20Ankara%20Ball%20Wedding%20Gown%20#therealrhonkefella.PNG",
story: "Today's my birthday next week! What do you think?",
user: "Chioma",
},
{
image: "https://dailymedia.com.ng/wp-content/uploads/2018/10/7915550_img20181007141132_jpeg01c125e1588ffeee95a6f121c35cd378-1.jpg",
story: "Going for an event. Do you like my outfit",
user: "Simpcy",
},
{
image: "https://i0.wp.com/www.od9jastyles.com/wp-content/uploads/2018/01/ankara-styles-ankara-styles-gown-ankara-tops-ankara-gowns-ankara-styles-pictures-latest-ankara-style-2018-latest-ankara-styles-ankara-ankara-styles.png?fit=437%2C544&ssl=1",
story: "Saturdays are for weddings. Yay or nay!",
user: "Angela",
},
]
So this could get you started:
https://codesandbox.io/s/1r7j6lom34?fontsize=14
I moved your static USER_UPLOAD into the state of Home and wrote a method to add a new upload to that state.
You would now need to come up with a component that shows your modal and calls AddUpload with the right values.
Also your card-actions don't seem to function properly. To fix that i suggest creating a wrapper component for Card that has a state with the appropriate click counters. That way every card has its own clickcounters.

Resources