changing style object at index of array in state in react - reactjs

i'm trying to update a style object inside my options array inside my apps state when an option is clicked in another component using toggleSelected (). Does anyone know how to best access the object and set the background color to something different?
App.js
this.state = {
options: [
{
id: 0,
label: "Industrial Truck and Tractor Operators",
value: "53-7051",
style: {
display: "flex",
margin: "auto",
paddingTop: "1em",
paddingBottom: "1em",
paddingLeft: "1em",
borderBottom: "solid",
borderColor: "black",
borderWidth: ".1em",
color: "#64bd9a",
backgroundColor: "white"
},
tooltip_text:
'Operate industrial trucks or tractors equipped to move materials around a warehouse, storage yard, factory, construction site, or similar location. Excludes “Logging Equipment Operators" (45-4022).'
},
{
id: 1,
label: "Order Clerks",
value: "43-4151",
style: {
display: "flex",
margin: "auto",
paddingTop: "1em",
paddingBottom: "1em",
paddingLeft: "1em",
borderBottom: "solid",
borderColor: "black",
borderWidth: ".1em",
color: "#64bd9a",
backgroundColor: "white"
},
tooltip_text:
'Receive and process incoming orders for materials, merchandise, classified ads, or services such as repairs, installations, or rental of facilities. Generally receives orders via mail, phone, fax, or other electronic means. Duties include informing customers of receipt, prices, shipping dates, and delays; preparing contracts; and handling complaints. Excludes "Dispatchers, Except Police, Fire, and Ambulance" (43-5032) who both dispatch and take orders for services.'
}
],
value: null,
styles: {
//container style is working
marginTop: "2em",
marginLeft: "2em",
borderStyle: "solid",
borderWidth: ".1em",
borderBottom: "none",
borderRight: "solid",
width: "19em",
textAlign: "justify",
backgroundColor: "white",
boxShadow: "3px 6px 5px #9E9E9E"
},
className: "",
selectedClassName: "",
loading_State: true, //this changes to false when the component loads
childrenCount: 0
};
toggleSelected = child => {
this.setProps({options.indexOf('1').style.backgroundColor: "gray" })
};
Component.js
render() {
return (
<div style={this.props.styles}>
{this.props.options.map(option => (
<div
key={option}
id={"option" + option.id}
style={option.style}
onClick={e => {
if (this.props.setProps) {
this.props.setProps({ value: e.target.value });
} else {
this.setState({ value: e.target.value });
}
this.props.toggleSelected(option.id); //passing my index here to the function
}}
>
<span id={option.id}> {option.label} </span>
<UncontrolledTooltip
placement="right"
target={"option" + option.id}
>
{option.tooltip_text}
</UncontrolledTooltip>
</div>
))}
</div>
);
}
Am I going about this the right way in terms of updating the styles object here. Should I use a different approach. Also I would like to do this without using CSS so adding classNames is not what I want to do.

I believe the following should work, assuming childIndex here represents the index of the state.options array that you want to modify.
toggleSelected = (childIndex) => {
const newOptions = this.state.options.map((option, i) => {
if (i !== childIndex) {
return option;
}
return {
...option,
style: {
...option.style,
backgroundColor: "green" // your color here
}
}
});
this.setState({ options: newOptions });
}
Edit: If you need to change all the other colors to white, you can do the following:
toggleSelected = (childIndex) => {
const newOptions = this.state.options.map((option, i) => {
return {
...option,
style: {
...option.style,
backgroundColor: i === childIndex ? "green" : "white"
}
}
});
this.setState({ options: newOptions });
}

Related

Trying to get Yup validation working on Controller and custom components based on react-select for overall form validity and error style

New to React here so I do appreciate any insight others may have on this.
I am trying to validate a custom select component based on react-select. I am having trouble with the following:
Showing the error styling for the select field while also having it work for the overall form validity. I am using react-hook-form and Yup validation.
I have a custom component here called CreditAppCustomSelect:
import { TextField } from '#mui/material';
import Image from 'next/image';
import React from 'react';
import Select, { components } from 'react-select';
import Arrow from '../../assets/images/icon/Icon.png';
export interface CustomStyles {
isHover: boolean;
isFocused: boolean;
isSelected: boolean;
}
const colourStyles = (isError: boolean) => ({
control: (styles: object, { isHover, isFocused }: CustomStyles) => {
return {
...styles,
borderRadius: '0px',
backgroundColor: 'white',
border: isFocused
? '0.1875rem solid #00B0C7'
: isError
? '0.1875rem solid #F6AE55'
: '0.1875rem solid #000000',
boxShadow: isHover ? '0.1875rem solid #00B0C7' : undefined,
'&:hover': {
border: isHover ? '0.1875rem solid #00B0C7' : undefined,
},
fontFamily: 'Avenir',
fontStyle: 'normal',
fontWeight: 500,
fontSize: '1.25rem',
/* or 30px */
color: '#969696',
textTransform: 'capitalize',
'#media only screen and (max-width:991px)': {
// #ts-ignore
...styles['#media only screen and (max-width:991px)'],
height: '3rem',
},
minHeight: '3rem',
};
},
dropdownIndicator: (
styles: object,
{ isFocused, isSelected, isHover }: CustomStyles
) => {
return {
color: '#242424',
marginInline: '0.2rem',
width: '0.625rem',
minWidth: '0.5rem',
};
},
option: (styles: object, { isFocused, isSelected }: CustomStyles) => {
return {
...styles,
backgroundColor: isFocused ? '#BBE8EE' : undefined,
color: 'black',
cursor: 'default',
'&:active': {
backgroundColor:
isSelected || isFocused ? 'rgba(176, 117, 251, 0.3)' : undefined,
},
};
},
menu: (styles: object) => {
return {
...styles,
boder: '0.0625rem solid #242424',
outline: '0.0625rem solid #242424',
color: '#242424',
// top: "0rem",
margin: '0 0.0625rem',
boxSizing: 'border-box',
width: 'calc(100% - 2px)',
borderRadius: '0px',
zIndex: 99,
fontFamily: 'Avenir',
fontStyle: 'normal',
fontWeight: 500,
fontSize: '1.25rem',
textTransform: 'capitalize',
};
},
input: (styles: object) => ({
...styles,
fontSize: '1.25rem',
}),
placeholder: (styles: object) => {
return {
...styles,
fontFamily: 'Avenir',
fontStyle: 'normal',
fontWeight: 500,
fontSize: '1.25rem',
/* or 30px */
color: '#969696',
textTransform: 'capitalize',
};
},
container: (
styles: object,
{ isFocused, isSelected, isHover }: CustomStyles
) => {
return {
...styles,
// borderRadius: "4px",
outline: 'none',
height: '3rem',
};
},
singleValue: (styles: object, { isFocused, isSelected }: CustomStyles) => {
return {
...styles,
fontSize: '1.25rem',
color: '#211e3b',
};
},
valueContainer: (styles: object) => {
return {
...styles,
paddingLeft: '0.75rem',
};
},
});
const CreditAppCustomSelect = (props: any) => (
<div className='credit-app-select-container'>
<label className={props.isError ? 'error' : ''}>
{props.label}
<Select
{...props}
styles={colourStyles(props.isError)}
components={{
IndicatorSeparator: () => null,
// eslint-disable-next-line #next/next/no-img-element
DropdownIndicator: (props) => (
<components.DropdownIndicator {...props}>
<Image src={Arrow} alt='down' />
</components.DropdownIndicator>
),
}}
isSearchable={false}
placeholder={props.placeholder}
onChange={props.onChange}
value={props.value} // This can be set like this as a result of the change
/>
{props.isError ? <span>{props.message}</span> : ''}
</label>
</div>
);
export default CreditAppCustomSelect;
in my form schema I have the following - one works for overall form validity and the other works for error styling - I know I can't use both so not sure what to do?:
// this works for overall form validity based on having a selected value (isValid)
employeeNumbers: Yup.object().shape({
label: Yup.string().nullable().required('Required'),
value: Yup.string().nullable().required('Required'),
}),
// the following works for the error styling and message but I know I can't do both this and the above
// employeeNumbers: Yup.string().nullable().required('Required'),
I am using a Controller around the CreditAppCustomSelect component:
<Controller
defaultValue=''
control={control}
{...register('employeeNumbers', { required: true })}
render={({ field }: any) => (
<CreditAppCustomSelect
{...field}
label='Number of Employees/Contractors'
name='employeeNumbers'
placeholder='Select range'
isError={
errors.employeeNumbers &&
errors.employeeNumbers.type === 'required'
}
message={'Required'}
options={numberEmployeesOptions}
/>
)}
/>
The options look like this
const numberEmployeesOptions = [
{ label: '1 - 4', value: '1 - 4' },
{ label: '5 - 9', value: '5 - 9' },
{ label: '10 - 19', value: '10 - 19' },
{ label: '20 - 49', value: '20 - 49' },
{ label: '50 - 99', value: '50 - 99' },
{ label: '100+', value: '100+' },
];
in the interface for the form I have the following for employee numbers:
employeeNumbers: { label: string; value: string };
I have not posted the entire form since it is so long but I am using mode:onBlur for the overall form and working in tsx files. Just trying to reconcile how I can achieve both form validity as well as error styling. I have searched for related issues in StackOverflow and I know there probably are solutions but have not yet managed to solve this and have been spinning my wheels for a while.
Thanks for any suggestions anyone may have!

How to change the Background Color of the Ant-Design 'Select' component?

Suppose I want to change the standard white background color of the Select component dynamically based on selection. I found a solution
on the internet .ant-select-selection { background-color: green; } but this is static.
It should be like this:
Here is my codesandbox link
Here is a sample code:
const RBICOptions = [
{
background: "#00CC00",
color: "#fff",
title: "Low",
value: "low"
},
{
background: "#FFFF00",
color: "#000",
title: "Medium",
value: "medium"
},
{
background: "#FFC000",
color: "#000",
title: "High",
value: "high"
},
{
background: "#FF0000",
color: "#fff",
title: "Very High",
value: "very_high"
}
];
const App: React.FC = () => {
const [selectedIPSS, setSelectedIPSS] = useState("#fff");
console.log("selectedIPSS", selectedIPSS);
return (
<Select
style={{
width: "50vw",
marginBottom: "5%",
backgroundColor: selectedIPSS
}}
onChange={(_, option) => {
setSelectedIPSS("style" in option ? option.style.background : "#fff");
}}
>
{RBICOptions.map((op) => (
<Select.Option
key={op.value}
value={op.value}
style={{ background: op.background, color: op.color }}
>
{op.title}
</Select.Option>
))}
</Select>
);
};
Please help me out with this issue. Thanks in advance.
Its because the ant-select class already defines a white background. You can remove it with setting the style to inherit:
.ant-select:not(.ant-select-customize-input) .ant-select-selector {
background-color: inherit;
}
Here is a codesandbox: https://codesandbox.io/s/select-with-search-field-antd-4-24-1-forked-rzln9z?file=/index.css:0-99

Click handler issue in React

I have written useState. The console log works, but even though the filter is correct, it doesn't change after the click. May I attach any clickHandler as a constant to an icon or div or section?
The <Task /> is added in the main container.
import React, { useState } from "react";
import { FaTimes } from "react-icons/fa";
const Task = () => {
const deleteTask = (id) => {
setTasks(tasks.filter((task) => task.id !== id));
console.log("deleted");
};
const [tasks, setTasks] = useState([
{ id: 1, text: "Football", reminder: true, day: " -March 22th at 20:30" },
{
id: 2,
text: "Lunch Meeting",
day: " -May 4th at 16:45",
reminder: true,
},
{
id: 3,
text: "Holliday in Bahamas",
reminder: true,
day: " -July 25th at 00:00",
},
]);
return (
<div>
{tasks.map((task) => (
<h3
key={task.id}
style={{
margin: "20px",
backgroundColor: "#cee1f4",
justifyContent: "center",
}}
>
{task.text}
<FaTimes
onClick={deleteTask}
style={{
color: " red",
paddingLeft: "370px",
position: "absolute",
display: "flex",
margin: "-8px 57px",
cursor: "pointer",
}}
/>
<p>{task.day}</p>
</h3>
))}
</div>
);
};
export { Task };
In <FaTimes> component, your onClick does not pass an ID, as is required by that function's parameter input.
This should work:
<FaTimes
onClick={() => deleteTask(task.id)}
style={{
color: " red",
paddingLeft: "370px",
position: "absolute",
display: "flex",
margin: "-8px 57px",
cursor: "pointer",
}}
/>

How to select only one day in react-big-calendar month view

I'm using react-big-calendar for calendar purpose in month view. https://github.com/jquense/react-big-calendar and i want to implement Add a new event by clicking on any cell (day) and i'm not sure what props should i use.
I know onSelectEvent will select only existing events no the entire day and this is not what i need and also selectable={true} will enable multi-selecting which in my case is useless.
so i need something like onDayClick or something but i wasn't so much lucky so far
I finally came up with using onSelectSlot and hiding multi-selecting effect manually using css, it's not perfect but its working!
<BigCalendar
view="month"
onNavigate={onNavigate}
culture="en-GB"
date={currentDate}
selectable={true}
onSelectEvent={onSelectEvent}
onSelectSlot={onSelectSlot}
onView={() => {}}
localizer={localizer}
events={events}
/>
Using end of selected slot as selected day: (I know it's not perfect!)
const onSelectSlot = (slotInfo: {
start: stringOrDate;
end: stringOrDate;
slots: Date[] | string[];
action: 'select' | 'click' | 'doubleClick';
}) => {
// use moment(slotInfo.end) as selected day!
};
Hiding multi-selecting effect using css:
calendar: {
'& > .rbc-calendar': {
width: '100%',
minHeight: '500px',
},
'& .rbc-month-view': {
border: 'none',
'& .rbc-event': {
paddingLeft: '2px',
borderRadius: 3,
backgroundColor: theme.palette.secondary.main,
},
'& .rbc-now': {
color: theme.palette.secondary.main,
},
'& .rbc-selected-cell': {
backgroundColor: '#fff',
},
'& .rbc-today.rbc-selected-cell': {
backgroundColor: '#eaf6ff',
},
'& .rbc-off-range-bg.rbc-selected-cell': {
background: '#e6e6e6',
},
'& .rbc-month-row': {
cursor: 'pointer',
},
},
},
You can do it like this it will work.
I just made a modal popup on click of a slot, you can put an alert or a console log
const handleSelectSlot = (start) => {
this.getModalData(start);
this.setState({ modalOpen: true });
this.setState({ valueIntoModal: start.start });
};
<Calendar
selectable={true}
formats={formats}
localizer={localizer}
events={[
...this.state.submittedData.data,
...this.state.savedData.data,
]}
view="month"
views={["month"]}
onSelectSlot={handleSelectSlot}
startAccessor="start"
endAccessor="end"
/>

Applying specific theme for react material-table

I'm trying to integrate react material-table (https://github.com/mbrn/material-table) with my project.
I want to update the styling/theme.
I used something like.
<MaterialTable options={{
rowStyle: x => {
if ( x.id % 2 ) {
return { backgroundColor: "#f2f2f2" }
}
},
'headerStyle' : {
backgroundColor: 'red',
color: theme.palette.common.white
}
}}
columns={columns}
data={data}
title="New Table"
/>
However I want to have a generic styling and theme like
const CustomTableCell = withStyles(theme => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
Basically i want to have something like CustomMaterialTable which is nothing but my theme/style.
Striping the table rows.
In the above code snippet, I used a logic to have striped rows.
if ( x.id % 2 ) {
return { backgroundColor: "#f2f2f2" }
}
Since my table will be having sorting, I want the it to be on a auto generated row id rather than x.id (where x is my data).
I want to use rtl and text in multiple languages based on the language selection (dynamic).
You can overrides components. Look at example: https://mbrn.github.io/material-table/#/docz-examples-10-example-component-overriding
Can you try x.tableData.id instead of x.id, please?
You should use material-ui theme with direction (ltr or rtl): https://material-ui.com/customization/themes/
you can use material-UI makeStyles for changing material-table theme.
This example when I'm changing the look for material-table
I implemented striped rows using
'&:nth-child(even)': {
backgroundColor: '#FAF7FA',
},
because when using rowStyle and after changing the table sorting, the stripped rows remain attached to their main fields.
Here is the full example:
export const useClasses = makeStyles(({ palette }) => ({
root: {
borderTopRightRadius: '12px',
borderTopLeftRadius: '12px',
boxShadow: '0px 5px 40px rgb(0 0 0 / 10%)',
fontFamily: 'Montserrat',
overflow: 'hidden',
'& .MuiPaper-root ': {
boxShadow: 'none',
},
'& .MuiTable-root': {
color: palette.text.textPrimary,
'& .MuiTableHead-root': {
'& .MuiTableRow-head': {
'& .MuiTableCell-head': {
background: 'rgba(90, 0, 90, 0.09)',
color: palette.text.textPrimary,
},
},
},
'& .MuiTableRow-root': {
'&:nth-child(even)': {
backgroundColor: '#FAF7FA',
},
},
},
},
}));

Resources