-2

I am attempting to populate drop down list dynamically. The list contains of states that are available in database . I am not supposed to add all 50 states, just the ones in the database , hence why this has to be dynamic.

This is not working because there is no 'add' function available to 'dropdown' element. Here is the error:

Project-fields.js:104 Uncaught (in promise) TypeError: e.add is not a function

The error is pointing to the line 'dropdown.add(options);'

This is the JSON object I receive upon fetch():

STATES: [{"_id":"Virginia","name":"Virginia","abbreviation":"VN","__v":0},{"_id":"North Carolina","name":"North Carolina","abbreviation":"NC","__v":0},{"_id":"Texas","name":"Texas","abbreviation":"TX","__v":0},{"_id":"Louisiana","name":"Louisiana","abbreviation":"LA","__v":0},{"_id":"5f1ef364691bf8c340104c18","name":"California","abbreviation":"CA"}

My Code :

function StateSelect({ values, initial }) {

 async function fetchStates(){
        let dropdown = document.getElementById('select');
        dropdown.length = 0;
        .then(
            function(response){
                if(response.status !== 200)
                {
                  console.warn('State Object Not Fetched' + response.status);
                  return;
                }

                response.json().then(function(data){
                    
                    console.log(`STATES: ${JSON.stringify(data)}`);
                    for(let i = 0; i < data.length; i++)
                    {
                        options = document.createElement('option');
                        options.value = data[i].name;
                        options.label = data[i].name;
                      // setOptions(data[i].name);
                      dropdown.add(options);
                        console.log(`OPTION: ${options}`);

                    }
                })
            }
        )

        
    }
useEffect(() => {
        
        fetchStates();
},[]);
          
return (
        <div className='attribute-edit-container'>
            <div className='attribute-name'>{'State'}</div>
            <Select id="select">
            </Select>
       );
} //StateSelect

Please help. Thank you

user1462617
  • 413
  • 1
  • 13
  • 23
  • Does this answer your question? [How do I create a dynamic drop down list with react-bootstrap](https://stackoverflow.com/questions/36205673/how-do-i-create-a-dynamic-drop-down-list-with-react-bootstrap) – Parth Shah Jul 30 '20 at 17:13
  • You are manipulating the DOM, but that's not how React works. You need `const [states, setStates] = useState([])` and use list rendering to turn `states` into a bunch of options in your JSX. Then call `setState()` and pass the array of states after your fetch has loaded them. A key concept of React is following the "separation of content and presentation" paradigm. –  Jul 30 '20 at 17:15

2 Answers2

1

I dont understand why if you use react to build your fontend you use document.createElement to manipulate the DOM.

With react you can render the components according to the state, try to chain the promises in the correct way, my correction to your code is this:

function StateSelect({ values, initial }) {
  const [dataFetch, setDataFetch] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  async function fetchStates() {
    setIsLoading(true);
    fetch('url')
      .then(response => {
        if (response.status !== 200) {
          console.warn('State Object Not Fetched' + response.status);
          return new Error(response.status);
        }
        return response.json();
      })
      .then(data => {
        console.log(`STATES: ${JSON.stringify(data)}`);
        setDataFetch(data);
        setIsLoading(false);
      })
      .catch(err => {
        setIsLoading(false);
        setError(err);
      });
  }

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

  return isLoading ? (
    <div>Loading</div>
  ) : error ? (
    <div>error</div>
  ) : (
    <div className='attribute-edit-container'>
      <div className='attribute-name'>{'State'}</div>
      <Select id='select'>
        {dataFetch.length > 0 &&
          dataFetch.map(item => (
            <option key={item._id} value={item.name}>
              {item.name}
            </option>
          ))}
      </Select>
    </div>
  );
}
Marco Mesen
  • 653
  • 6
  • 12
  • Thanks for your response. But dataFetch is always empty.. I added console.log to verfiy and it always returns an empty array. As a result I am always getting an empty drop down. – user1462617 Jul 30 '20 at 21:34
  • Always will be empty, you need to use fetch with a correct parameter, in your first code you use `.then` without fetch, you need to use fetch correctly – Marco Mesen Jul 30 '20 at 21:39
  • I would appreciate if you could help me understand this. Please can you elaborate or show an example of what you meant. My understanding is in the second '.then' when we call setDataFetch(data) that would set dataFetch's value. I verified there is data in 'data'. And as I mentioned in the original post the fetch() is working. I am receiving a valid JSON object. – user1462617 Jul 30 '20 at 21:52
  • Yes, I can help you, look, in your first code in the line 6 after you write `dropdown.length = 0` you use `.then`it is a mistake, because you dont call any fetch data. To help you, i need understand where you want yo fetch data to build the options, and you need to learn how use fetch function if you want yo call a api to build your options – Marco Mesen Jul 30 '20 at 22:01
  • Ahh, my bad. I accidentally missed the fetch statement when copying, pasting code here. But in the altered/updated code that you have provided, can you help me understand that because dataFetch comes out empty and so does the – user1462617 Jul 30 '20 at 22:07
0

You are not supposed to manipulate the DOM with react. Just create your drop down menu and then map through the objects and return that value

{states.map((state) => {
    return <MenuItem value={state._id}>{state.name} 
</MenuItem>;
})}