After entering the color name in the input field, when I submit the form, an error occurs :
TypeError: Cannot read property 'toLowerCase' of undefined (anonymous function) C:/Users/HP/Documents/WDB/React/Practice/colors-app/src/NewPaletteForm.js:117
114 | //to check -> is 'palette name' unique
115 | ValidatorForm.addValidationRule("isPaletteNameUnique", value => {
116 | return palettes.every(
> 117 | ({ paletteName }) => paletteName.toLowerCase() !== value.toLowerCase()
118 | ^ );
119 | });
120 | })
App.js : (Class-based component)
class App extends Component {
constructor(props) {
super(props);
this.state = { palettes: seedColors };
this.findPalette = this.findPalette.bind(this);
this.savePalette = this.savePalette.bind(this);
}
savePalette(newPalette) {
this.setState({ palettes: [...this.state.palettes, newPalette] });
}
render() {
return (
<Switch>
<Route
exact
path='/palette/new'
render={(routeProps) =>
<NewPaletteForm
savePalette={this.savePalette}
palettes={this.state.palettes}
{...routeProps}
/>}
/>
NewPaletteForm.js : (Functional component and uses react hooks)
function NewPaletteForm(props) {
const classes = useStyles();
const [open, setOpen] = useState(false);
const [currentColor, setCurrentColor] = useState('teal');
const [colors, setColors] = useState([{ color: 'pink', name: 'pink' }]);
const [fields, setFields] = useState({
newColorName: '',
newPaletteName: ''
})
useEffect(() => {
ValidatorForm.addValidationRule('isColorNameUnique', (value) => {
return colors.every(
({ name }) => name.toLowerCase() !== value.toLowerCase()
);
});
ValidatorForm.addValidationRule('isColorUnique', (value) => {
return colors.every(
({ color }) => color !== currentColor
);
});
ValidatorForm.addValidationRule("isPaletteNameUnique", value => {
return props.palettes.every(
({ paletteName }) => paletteName.toLowerCase() !== value.toLowerCase()
);
});
})
function addNewColor() {
const newColor = {
color: currentColor,
name: fields.newColorName
}
setColors(oldColors => [...oldColors, newColor]);
setFields({ newColorName: '' });
};
function handleChange(evt) {
setFields({ ...fields, [evt.target.name]: evt.target.value });
}
function handleSubmit() {
let newName = fields.newPaletteName;
const newPalette = {
paletteName: newName,
id: newName.toLowerCase().replace(/ /g, '-'),
colors: colors
}
props.savePalette(newPalette);
props.history.push('/');
}
Validator form components for colors and palettes :
<ValidatorForm onSubmit={handleSubmit}>
<TextValidator
label='Palette Name'
value={fields.newPaletteName}
name='newPaletteName'
onChange={handleChange}
validators={['required', 'isPaletteNameUnique']}
errorMessages={['Enter Palette Name', 'Name already used']} />
<Button variant='contained' color='primary' type='submit'>
Save Palette
</Button>
</ValidatorForm>
<ValidatorForm onSubmit={addNewColor}>
<TextValidator
value={fields.newColorName}
name='newColorName'
onChange={handleChange}
validators={['required', 'isColorNameUnique', 'isColorUnique']}
errorMessages={['Enter a color name', 'Color name must be unique', 'Color already used!']}
/>
<Button
variant='contained'
type='submit'
color='primary'
style={{
backgroundColor: currentColor
}}
>
Add Color
</Button>
</ValidatorForm>
seedColors.js:
export default [
{
paletteName: "Material UI Colors",
id: "material-ui-colors",
emoji: "🎨",
colors: [
{ name: "red", color: "#F44336" },
{ name: "pink", color: "#E91E63" },
{ name: "purple", color: "#9C27B0" },
{ name: "deeppurple", color: "#673AB7" },
{ name: "indigo", color: "#3F51B5" },
{ name: "blue", color: "#2196F3" },
{ name: "lightblue", color: "#03A9F4" },
{ name: "cyan", color: "#00BCD4" },
{ name: "teal", color: "#009688" },
{ name: "green", color: "#4CAF50" },
{ name: "lightgreen", color: "#8BC34A" },
{ name: "lime", color: "#CDDC39" },
{ name: "yellow", color: "#FFEB3B" },
{ name: "amber", color: "#FFC107" },
{ name: "orange", color: "#FF9800" },
{ name: "deeporange", color: "#FF5722" },
{ name: "brown", color: "#795548" },
{ name: "grey", color: "#9E9E9E" },
{ name: "bluegrey", color: "#607D8B" }
]
},
{
paletteName: "Flat UI Colors v1",
id: "flat-ui-colors-v1",
emoji: "🤙",
colors: [
{ name: "Turquoise", color: "#1abc9c" },
{ name: "Emerald", color: "#2ecc71" },
{ name: "PeterRiver", color: "#3498db" },
{ name: "Amethyst", color: "#9b59b6" },
{ name: "WetAsphalt", color: "#34495e" },
{ name: "GreenSea", color: "#16a085" },
{ name: "Nephritis", color: "#27ae60" },
{ name: "BelizeHole", color: "#2980b9" },
{ name: "Wisteria", color: "#8e44ad" },
{ name: "MidnightBlue", color: "#2c3e50" },
{ name: "SunFlower", color: "#f1c40f" },
{ name: "Carrot", color: "#e67e22" },
{ name: "Alizarin", color: "#e74c3c" },
{ name: "Clouds", color: "#ecf0f1" },
{ name: "Concrete", color: "#95a5a6" },
{ name: "Orange", color: "#f39c12" },
{ name: "Pumpkin", color: "#d35400" },
{ name: "Pomegranate", color: "#c0392b" },
{ name: "Silver", color: "#bdc3c7" },
{ name: "Asbestos", color: "#7f8c8d" }
]
}
]
What you can do is check to see if the value
exists before calling toLowerCase.
Try using ?.
, like this
Instead of using value.toLowerCase()
use value?.toLowerCase()
.
That way if the value
is undefined or null, it won't call toLowerCase()
If paletteName
is the one failing you can use paletteName?.toLowerCase()
If you want to go completely safe you do
paletteName?.toLowerCase() !== value?.toLowerCase()