2

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" }
        ]
    }
]
Ashmita Singh
  • 69
  • 2
  • 2
  • 11
  • 1
    Which of `paletteName.toLowerCase() !== value.toLowerCase()` is undefined? What debugging have you tried already? It seems either `paletteName` isn't a property on the elements in the `palettes` prop, or `value` is undefined. Since `value` seems to be defined above in the other validations it seems that `palettes` isn't the value you expect. Can you share what `seedColors` is? I suspect you're seeing this issue on the initial render, or close to it? – Drew Reese Aug 10 '21 at 06:47
  • check once seedColors, it have paletteName ? – Akash Gupta Aug 10 '21 at 06:58
  • I've added the seedColors.js file – Ashmita Singh Aug 10 '21 at 06:59
  • Add a log and check what is the value of `paletteName` and `value` – Ayush Gupta Aug 10 '21 at 07:01

1 Answers1

6

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()
DJ Burb
  • 2,346
  • 2
  • 29
  • 38