How to loop data with that will have different styles? - javascript

How can I loop data that will have different styles such as colors and icons in a better way than the code below? The code below works but I want to have more categories to loop through and the code is getting long. Is there a better way to do this without changing the backend?
I'm using Next.js and Firebase for backend, map looping "Food" collection with product documents and categories in fields. Only one id in the food group can be true for each item.
{food.map((item, index) => (
<div key={index}>
{/* Fruits category*/}
{Object.keys(item.fruitsCategory).length > 0 && (
<div>
{/* Apples */}
{item.fruitsCategory.category.id === 1 && (
<div className="flex gap-2">
<AppleIcon />
<p className="text-[#1BAB33]">Apples</p>
</div>
)}
{/* Bananas */}
{item.fruitsCategory.category.id === 2 && (
<div className="flex gap-2">
<BananaIcon />
<p className="text-[#C6B027]">Bananas</p>
</div>
)}
{/* Oranges */}
{item.fruitsCategory.category.id === 3 && (
<div className="flex gap-2">
<OrangeIcon />
<p className="text-[#FAB71A]">Oranges</p>
</div>
)}
{/* Strawberries */}
{item.fruitsCategory.category.id === 4 && (
<div className="flex gap-2">
<StrawberryIcon />
<p className="text-[#D13131]">Strawberries</p>
</div>
)}
{/* Meat category */}
{Object.keys(item.meatCategory).length > 0 && (
<div>
{/* Cow meat */}
{item.meatCategory.category.id === 1 && (
<div className="flex gap-2">
<CowIcon />
<p className="text-[#006989]">Cow meat</p>
</div>
)}
{/* Chicken meat */}
{item.meatCategory.category.id === 2 && (
<div className="flex gap-2">
<ChickenIcon />
<p className="text-[#01A7C2]">Chicken meat</p>
</div>
)}
{/* Pig meat */}
{item.meatCategory.category.id === 3 && (
<div className="flex gap-2">
<PigIcon />
<p className="text-[#18AFC8]">Pig meat</p>
</div>
)}
</div>
)}
</div>
)}

Related

IonSlides render something on lastSLide. Ionic React

I want to dynamically show my buttons when i get to the lastSlide, but it dies not seems to work.
I'm trying to use FindIndex to find someText that is actually on the lastSlide and nothing happens
The console prints out 4 because i have 5 items in the Array which is correct, but i can't render something to the dom
if there's any other options in the IonSlides Component itself, i will appreciate, because onSlideReachEnd event that ionic provides does not work.
const lastIndex = slideContent.findIndex((element) => {
if (element.slideTitle === "Safe & Secure") {
return true;
}
return false;
});
console.log(lastIndex); // 4
return (
<IonPage>
<div className="content">
<IonSlides pager={true} options={slideOpts}>
{slideContent.map((slide, idx) => (
<IonSlide key={idx}>
<div>
<img
src={slide.slideImage}
alt={slide.slideAltText}
className={slide.slideClassName}
/>
<IonText>
<h5 className="mb-1 fw-bold">{slide.slideTitle}</h5>
</IonText>
<IonText color="primary" className="fw-bold">
<h4 className="mt-0 bold h4"> {slide.slidePrimaryText} </h4>
</IonText>
<div className="pt-0 px-5 pb-4">
<IonText>
<h6 className="fs-md mb-6 line-h fw-sm fw-reg tet-color">
{slide.slideText}
{slide.slideSecoundaryText && (
<IonText color="primary" className="fw-bold ">
<h6 className="mt-0 fs-md bold mt-3">
{slide.slideSecondaryText}
</h6>
</IonText>
)}
</h6>
</IonText>
{slide.slideBtn && (
<IonButton
shape="round"
fill="clear"
className="btn f-inherit"
size="small"
>
Stuff
</IonButton>
)}
{idx}
</div>
</div>
</IonSlide>
))}
</IonSlides>
</div>
{lastIndex && (
<div className="ion-padding">
<IonGrid>
<IonRow>
<IonCol size="6">
<IonButton
expand="block"
className="btn"
size="small"
onClick={() => navigate("/login", "forward")}
>
Login
</IonButton>
</IonCol>
<IonCol size="6">
<IonButton
expand="block"
fill="outline"
onClick={() => navigate("/get-started", "forward")}
className="btn"
size="small"
>
Get Started
</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</div>
)}
</IonPage>
);
const SlidePage = () => {
const [isLastSlide, setIsLastSlide] = useState();
const slideChanged = async e => {
const r = await e.target.isEnd();
setIsLastSlide(r);
console.log("isEnd", r);
};
return (
<IonPage>
<IonContent>
<IonSlides pager={true} onIonSlideDidChange={slideChanged}>
<IonSlide>
<h1>Slide 1</h1>
</IonSlide>
<IonSlide>
<h1>Slide 2</h1>
</IonSlide>
<IonSlide>
<h1>Slide 3</h1>
</IonSlide>
</IonSlides>
{isLastSlide && <h1 style={{ textAlign: "center" }}>IS LAST SLIDE</h1>}
</IonContent>
</IonPage>
);
listen for slide change event and update the state if it is the last slide.
onIonSlideDidChange
working example here on stackblitz - https://stackblitz.com/edit/react-w5gawb?file=src%2FApp.js

React: Map data horizontally

I have some data that I am mapping into cards. By default they are mapped vertically under each other (see the screenshot below). However, I would like them to be mapped horizontally next to each other. Is there a way to achieve this?
Here is my code:
return (
<div>
{this.state.serials.map((number) => {
return number.s && number.s.length? (
<div>
<Card className="card" style={{ width: '18rem' }}>
<Card.Body>
<div className="row">
<div className="col">
<h2>{number.s[0].l}</h2>
</div>
<div className="vl"></div>
<div className="col">
<h4>{number.s[0].d[0]}</h4>
{number.s[0].ta}
<FontAwesomeIcon onClick={()=>this.deleteCard(number.s[0].ta)} icon={faTrashAlt} />
</div>
</div>
</Card.Body>
</Card>
<p></p>
</div>
) : null
})}
</div>
);
Thanks in advance!
If you mean you want to put the Card in
X Y Z
instead of
X
Y
Z
then I would recommend putting a container with a display: flex
return (
<div class="container" style={{display: "flex"}}>
{this.state.serials.map((number) => {
return number.s && number.s.length? (
<div>
<Card className="card" style={{ width: '18rem' }}>
<Card.Body>
<div className="row">
<div className="col">
<h2>{number.s[0].l}</h2>
</div>
<div className="vl"></div>
<div className="col">
<h4>{number.s[0].d[0]}</h4>
{number.s[0].ta}
<FontAwesomeIcon onClick={()=>this.deleteCard(number.s[0].ta)} icon={faTrashAlt} />
</div>
</div>
</Card.Body>
</Card>
<p></p>
</div>
) : null
})}
</div>
);
Try setting "flex-direction: row" on outer div (above the map function) or provide more info about "this.state.serials" data...
Example
.container{
display: flex;
flex-direction: row;
}

How can I render multiple elements after an inline condition using short circuit evaluation?

Using a short circuit evaluation in a functional component (with hooks):
const Filters = () => {
const [options, setOptions] = useState([]);
return (
<div className="row">
{options.length > 0 && (
<div className="col-md-3">
<CustomComponent />
</div>
)}
</div>
)
}
Is there a way to render multiple elements right after an inline if condition?
{options.length > 0 && (
<div className="col-md-3">
<CustomComponent />
</div>
<div className="col-md-3">
<SecondComponent />
</div>
)}
Code above doesn't work, react throws an error. options array is filled after a promise resolved from useEffect(). That's why i've added this check, to display elements only when a promise resolved.
UPDATED CODE for #wentjun:
return (
{options.length > 0 && (
<div className="row">
<div className="col-md-3">
<CustomComponent />
</div>
</div>
)}
)
This throws a syntax error.
I think the error is due to returning two react elements. Try wrapping then in fragment
{options.length > 0 && (
<>
<div className="col-md-3">
<CustomComponent />
</div>
<div className="col-md-3">
<SecondComponent />
</div>
</>
)}
You should wrap the elements in React Fragments. The reason being, React elements are rendered via a single root node element. Wrapping it in Fragments will allow you to group the elements without adding additional nodes.
return (
<div className="row">
{options.length > 0 && (
<>
<div className="col-md-3">
<CustomComponent />
</div>
<div className="col-md-3">
<SecondComponent />
</div>
</>
)}
</div>
)

Several ternary operators nested within

There is a syntax error {} when I added {this.state.items && this.state.items.length? under <div className =" container ">. When I remove this extreme condition {this.state.items && this.state.items.length? : Components : <Preloader />everything works.A lot of nesting and I don't know exactly where the problem is. I think it is an extreme condition. Instead of the main component on the whole page I want to render the preloader on the whole page
class Items extends Component {
render () {
return (
<div className="container">
{this.state.items && this.state.items.length ?
<div className="items">
<div className="item">
<span>
<i></i>
</span>
<h4></h4>
<div className="select">
<button></button>
</div>
</div>
<div className="section">
<input/>
<span>
<i></i>
</span>
</div>
<div>
'AAAAAAA'
</div>
<div className="scroll">
{this.state.items.length === 0 && this.state.status === 1 ?
<div className="array">
<p>AAAAAA</p>
</div>
:
this.state.items && this.state.items.length ?
this.state.items.map((todo, index) =>
<Item
key={item.id}
index={index}
/>
)
:
<div className="preloader">
</div>
}
</div>
</div>
<div className="another">
<Component1
/>
<Component2
/>
</div>
:
<Preloader />
</div>
)
}
}
You were missing an } before the last div to close the first ternary and you were missing a wrapping tag for the first ternaries first expression (I used a React.Fragment). Code snippet bellow should be syntactically correct. I do recommend you refactor your code though.
class Items extends Component {
render() {
return (
<div className="container">
{this.state.items && this.state.items.length ? (
<React.Fragment>
<div className="items">
<div className="item">
<span>
<i></i>
</span>
<h4></h4>
<div className="select">
<button></button>
</div>
</div>
<div className="section">
<input />
<span>
<i></i>
</span>
</div>
<div>'AAAAAAA'</div>
<div className="scroll">
{this.state.items.length === 0 && this.state.status === 1 ? (
<div className="array">
<p>AAAAAA</p>
</div>
) : this.state.items && this.state.items.length ? (
this.state.items.map((todo, index) => (
<Item key={item.id} index={index} />
))
) : (
<div className="preloader"></div>
)}
</div>
</div>
<div className="another">
<Component1 />
<Component2 />
</div>
</React.Fragment>
) : (
<Preloader />
)}
</div>
);
}
}

Add Remove Class on Scroll ReactJs

I am stuck in this problem. I want to add/remove the class on a header element on scroll, but somehow I can not manage it.
I tried to mount and unmount (found few solutions here on Stack) but does not work in my case. Simply because in most of those cases the code relates to component but I have a little bit different set-up.
Here the full code:
https://codesandbox.io/s/angry-villani-lduor?fontsize=14
I want to add the new class on store_details_header
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};

Categories