1

I'm trying to create a dropdown select list that is dependent on it's parent list i.e Category and then a subcategory for a clothing catalogue. The plan is to then store that data in firestore but whenever i use map, I keep running into this error that tells me "Cannot read property 'map' of undefined". I've tried putting the map block in an if statement but that does'nt work either.

class Catalogue extends Component{
  
  constructor(){
    super();
    this.state={
      prodname:'',
      prodprice:'',
      prodcat:'',
      prodsize:'',
      proddetails:'',
      selectedView:'Men'

    };

  }
  updateInput = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  }
  
  addProd = e => {
    e.preventDefault();
    const db = firebase.firestore();
  
    const userRef = db.collection("Users").doc("User1").set({
        prodname: this.state.prodname,
        prodprice: this.state.prodprice,
        prodcat: this.state.prodcat,
        prodsize: this.state.prodsize,
        proddetails: this.state.proddetails,
    });  
    this.setState({
        prodname:'',
        prodprice:'',
        prodcat:'',
        prodsize:'',
        proddetails:'',
        selectedView:'Men'
    });
  };

  render(){

    //==================Subcategories Code====================//
    const { selectedView } = this.state
    const VIEWS = [
      {
        name: 'Men', 
        minor: ['Shirts', 'Pants']
      }, {
        name: 'Women', 
        minor: ['Shirt', 'Skirt']
      }
    ]
    const getMajorMethod = () => {
      const view = VIEWS.filter(({name}) => name === selectedView)
      return (
        <div>
          <select>
            {view.minor.map(m => <option>{m}</option>)}
          </select>
        </div>
      )
    }

    return(
      <div id="container">
            <Form onSubmit={this.addProd}>
      <FormGroup row>
        <Label for="prod_name" sm={2}>Product Name</Label>
        <Col sm={10}>
          <Input type="text" name="prodname" id="prod_name" onChange={this.updateInput} value={this.state.prodname}/>
        </Col>
      </FormGroup>
      <FormGroup row>
        <Label for="prod_price" sm={2}>Price Rs:</Label>
        <Col sm={10}>
          <Input type="number" name="prodprice" id="prod_price" onChange={this.updateInput} value={this.state.prodprice} />
        </Col>
      </FormGroup>
      <FormGroup row>
        <Label for="prod_cat" sm={2}>Category</Label>
        <Col sm={10}>
          <Input type="select" name="prodcat" id="prod_cat" onChange={this.updateInput} value={this.state.prodcat} >
           <option disabled="disabled" value="">Select Category</option>
           <option value="Men">Men</option>
           <option value="Women">Women</option>
          </Input>
        </Col>
      </FormGroup>

      <FormGroup row>
        <Label for="prod_subcat" sm={2}>Sub Category</Label>
        <Col sm={10}>
         <select onChange={(e) => this.setState({selectedView: e.target.value})}>
          {VIEWS.map(({name}) => <option value={name}>{name}</option>)}
         </select>
        {getMajorMethod()}
        </Col>
      </FormGroup>

      <FormGroup row>
        <Label for="prod_size" sm={2}>Size</Label>
        <Col sm={10}>
          <Input type="select" name="prodsize" id="prod_size" onChange={this.updateInput} value={this.state.prodsize}>
           <option disabled="disabled" value="">Select Size</option>
           <option value="S">S</option>
           <option value="M">M</option>
           <option value="L">L</option>
           <option value="XL">XL</option>
          </Input>
        </Col>
      </FormGroup>
      <FormGroup row>
        <Label for="prod_details" sm={2}>Product Details</Label>
        <Col sm={10}>
          <Input type="textarea" name="proddetails" id="prod_details" onChange={this.updateInput} value={this.state.proddetails} />
        </Col>
      </FormGroup>
      <FormGroup check row>
        <Col sm={{ size: 10, offset: 2 }}>
          <Button>Submit</Button>
        </Col>
      </FormGroup>
    </Form>

    </div>
    );
  }
}

export default Catalogue;
2
  • For which map statement you are getting error? Commented Nov 17, 2020 at 7:19
  • Here {view.minor.map(m => <option>{m}</option>)} Commented Nov 17, 2020 at 8:59

2 Answers 2

1

The array filter function returns an array, so view.minor is not valid, since view is an array.

You can use array.protoype.find instead to return the view object you want to access into and map the minor array of.

The find() method returns the value of the first element in the provided array that satisfies the provided testing function.

It can return undefined if no element in the array is found, so you will want to do a null check and conditionally render the select and options only if view is a defined object.

const getMajorMethod = () => {
  const view = VIEWS.find(({name}) => name === selectedView)
  return view ? (
    <div>
      <select>
        {view.minor.map(m => <option>{m}</option>)}
      </select>
    </div>
  ) : null
}
Sign up to request clarification or add additional context in comments.

Comments

0

It is because the view here const view = VIEWS.filter(({name}) => name === selectedView) contains only name and not minor. So when you try to get minor here {view.minor.map(m => <option>{m}</option>)} from view you are getting undefined

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.