5

I have a form in which I would like to render different fields based on a category which is selected from a dropdown. For instance in the following example, if there are categories named 'phones' and 'laptops, if 'laptops' is selected the form will include the field 'network' and if laptops' is selected, the form will include the field 'processor' (both are currently shown). What is the best way to go about doing this? I assume I would need to store the selected dropdown option in state and render the fields based on that, but I'm at a loss as to how to accomplish it without breaking what I currently have.

import React, { useState, useEffect } from "react";
import Layout from "../core/Layout";
import { isAuthenticated } from "../auth";
import { createProduct, getCategories } from './apiAdmin';

const AddProduct = () => {
  const [values, setValues] = useState({
    name: '', network: '',  processor: '', categories: [], category: '', loading: false, error: '', createdProduct: '', redirectToProfile: false, formData: ''
  });
  const { user, token } = isAuthenticated();
  const { name, network, processor, categories, category, loading, error, createdProduct, redirectToProfile, formData } = values;

  const init = () => {
    getCategories().then(data => {
      if (data.error) {
        setValues({ ...values, error: data.error });
      } 
      else {
        setValues({...values, categories: data, formData: new FormData() });
      }
    });
  };

  useEffect(() => {
    init();
  }, []);

  const handleChange = name => event => {
    const value = event.target.value;
    formData.set(name, value);
    setValues({ ...values, [name]: value });
  };

  const clickSubmit = (event) => {
    event.preventDefault();
    setValues({ ...values, error: '', loading: true });
    createProduct(user._id, token, formData)
      .then(data => {
        if (data.error) {
          setValues({ ...values, error: data.error });
        }
        else {
          setValues({ ...values, name: '', network: '', processor: '', loading: false, createdProduct: data.model });
        }
      });
  };

  const newPostForm = () => (
    <form className='mb-3' onSubmit={clickSubmit} >
      <div className='form-group'>
        <label className='text-muted'>Category</label>
        <select onChange={handleChange('category')} className='form-control'>
          <option>Select a Category</option>
          { categories && categories.map((c, i) => (<option key={i} value={c._id}>{c.name}</option>)) }
        </select> 
      </div>    
      <div className='form-group'>
        <label className='text-muted'>Name</label>
        <input 
          onChange={handleChange('name') } 
          type='text' 
          className='form-control' 
          value={name} 
        /> 
      </div>    

      // *****************************************************************************************
      // ************  THIS SHOULD BE RENDERED ONLY IF CATEGORY 'PHONES' IS SELECTED  ************
      // *****************************************************************************************

      <div className='form-group'>
        <label className='text-muted'>Network</label>
        <input 
          onChange={handleChange('network') } 
          type='text' 
          className='form-control' 
          value={network} 
        /> 
      </div>

      // *****************************************************************************************
      // ***********  THIS SHOULD BE RENDERED ONLY IF CATEGORY 'LAPTOPS' IS SELECTED  ************
      // *****************************************************************************************
      <div className='form-group'>
        <label className='text-muted'>Processor</label>
        <input 
          onChange={handleChange('processor') } 
          type='text' 
          className='form-control' 
          value={processor} 
        /> 
      </div>
      <button className='btn btn-outline-primary'>
        Submit
      </button>
    </form>
  );

  return (
    <Layout title='Add Product' description={`Welcome, ${user.name}.`} >
      <div className='row'>
        <div className='col-md-8 offset-md-2'>
          {newPostForm()}
        </div>
      </div>
    </Layout>
  )
}

export default AddProduct;
1
  • You can use conditional rendering here, that depends on the value of your name is equal to category @mxvx Commented Dec 30, 2019 at 17:07

2 Answers 2

3

This will help you.

formData.get("category") === "phones" ? <> PHONES DISPLAY DIV </> : formData.get("category") === "laptops" ? <> LAPTOPS DISPLAY DIV</> : null

Sign up to request clarification or add additional context in comments.

Comments

1

This should work for you:

const newPostForm = () => (

  return <form>

    { category === 'phones' && <div> YOUR PHONES FIELDS HERE </div> }

    { category === 'laptops' && <div> YOUR LAPTOP FIELDS HERE </div }

  </form>

);

2 Comments

Hi Joshua Beckers, Thanks for your suggestion , would considering "lazy import" the expected form a bad practice ? i mean what if we had hundreds of categories imagine the number of conditions we need to deal with ?
@HarvesterHaidar my proposed solution made sense for the question as asked. If you had more categories i would suggest using a different method depending on your needs. To answer your question, lazy loading the form fields wouldn't be in my eyes a bad practice. You could look into something like Redux Toolkit Query to load / cache them from a server for example.

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.