3

Question

How do I create a series (e.g. 2) dropdownboxes that depend on the choice in the previous dropdown box, while both being populated from MongoDB queries from within the Express framework?

Example functionality

 1. Create a MongoDB database with:
Volvo
Audi
Hyunday
 2. Create a second database with the colors of the cars, e.g.
Volvo:yellow,red
Audi:ultra-violet,green
Hyunday:purple,blue
 3. Show a webpage in localhost that displays a dropdown box with the 3 cars.
 4. When the user selects a car e.g. Volvo, the second dropdownbox should be populated by
the MongoDB query that returns the colours of that car; e.g. yellow,red.

MWE

A complete MWE is found here, you can run it with: npm start.

Attempts

In response to the comments I have reduced my nr. of listed attempts to a single one. It contains the queries to the MongoDB whose results are displayed on the hosted website as well as a function that removes/renames entries from a dropdownlist. The attempt is written in file ../client/src/app.js and contains:

// /client/App.js
import React, { Component } from 'react';
import axios from 'axios';

class App extends Component {
    
    // initialize our state
    state = {
        data: [],
        id: 0,
        message: null,
        intervalIsSet: false,
        idToDelete: null,
        idToUpdate: null,
        objectToUpdate: null,
    };
    
    // when component mounts, first thing it does is fetch all existing data in our db
    // then we incorporate a polling logic so that we can easily see if our db has
    // changed and implement those changes into our UI
    componentDidMount() {
        this.getDataFromDb();
        if (!this.state.intervalIsSet) {
            let interval = setInterval(this.getDataFromDb, 2000000);
            this.setState({ intervalIsSet: interval });
        }
    }
    
    // never let a process live forever
    // always kill a process everytime we are done using it
    componentWillUnmount() {
        if (this.state.intervalIsSet) {
            clearInterval(this.state.intervalIsSet);
            this.setState({ intervalIsSet: null });
        }
    }
    
    // just a note, here, in the front end, we use the id key of our data object
    // in order to identify which we want to Update or delete.
    // for our back end, we use the object id assigned by MongoDB to modify
    // data base entries
    
    // our first get method that uses our backend api to
    // fetch data from our data base
    getDataFromDb = () => {
        fetch('http://localhost:3001/api/getData')
                .then((data) => data.json())
                .then((res) => this.setState({ data: res.data }));
    };
    
    // our put method that uses our backend api
    // to create new query into our data base
    putDataToDB = (message) => {
        let currentIds = this.state.data.map((data) => data.id);
        let idToBeAdded = 0;
        while (currentIds.includes(idToBeAdded)) {
            ++idToBeAdded;
        }
        
        axios.post('http://localhost:3001/api/putData', {
            id: idToBeAdded,
            message: message,
        });
    };
    
    // our delete method that uses our backend api
    // to remove existing database information
    deleteFromDB = (idTodelete) => {
        parseInt(idTodelete);
        let objIdToDelete = null;
        this.state.data.forEach((dat) => {
            if (dat.id === idTodelete) {
                objIdToDelete = dat._id;
            }
        });
        
        axios.delete('http://localhost:3001/api/deleteData', {
            data: {
                id: objIdToDelete,
            },
        });
    };
    
    // our update method that uses our backend api
    // to overwrite existing data base information
    updateDB = (idToUpdate, updateToApply) => {
        let objIdToUpdate = null;
        parseInt(idToUpdate);
        this.state.data.forEach((dat) => {
            if (dat.id === idToUpdate) {
                objIdToUpdate = dat._id;
            }
        });
        
        axios.post('http://localhost:3001/api/updateData', {
            id: objIdToUpdate,
            update: { message: updateToApply },
        });
    };
    
    // option 9:
//    getOption(){
//        var select = document.getElementById("dynamic-select");
//        console.log(select);
//        if(document.getElementById("dynamic-select").options.length > 0) {
//            var option = document.getElementById("dynamic-select").options[document.getElementById("dynamic-select").selectedIndex];
//            alert("Text: " + option.text + "\nValue: " + option.value);
//        } else {
//            window.alert("Select box is empty");
//        }
//    }
    
    addOption(){
        var inputElemAdd = document.getElementsByTagName('select');
        var selectBox = document.getElementById("dynamic-select");
        alert("Current len="+Object.keys(inputElemAdd));
        alert("ID props="+Object.keys(selectBox)); // returns 3 props
        alert("ID props 2="+Object.keys(selectBox[2])); // returns 3rd array element (index 2)
        //alert("ID props 3 error="+Object.keys(selectBox[3])); // returns 3 props
        alert("label="+ selectBox[2].label); // returns 3rd array element (index 2)
        
        selectBox[0].label = "Wrote 0";
        selectBox[2].label = "Wrote 2";
        selectBox[3] = new Option('hi, added last label', 'id0',false,false); // add option
    }
    
    removeOption(){
        var inputElem = document.getElementsByTagName('select');
        for(var i = 0; i < inputElem.length; i++) {
               inputElem[i].options[inputElem[i].selectedIndex] = null; // remove option
        }
    }
//    
//    removeAllOptions(){
//        var select = document.getElementById("dynamic-select");
//        select.options.length = 0;
//    }
    
    // here is our UI
    // it is easy to understand their functions when you
    // see them render into our screen
    render() {
    const { data } = this.state;
    return (
      <div>
        <ul>
          {data.length <= 0
            ? 'NO DB ENTRIES YET'
            : data.map((dat) => (
                <li style={{ padding: '10px' }} key={data.message}>
                  <span style={{ color: 'gray' }}> id: </span> {dat.id} <br />
                  <span style={{ color: 'gray' }}> data: </span>
                  {dat.message}
                </li>
              ))}
        </ul>
        <div style={{ padding: '10px' }}>
          <input
            type="text"
            onChange={(e) => this.setState({ message: e.target.value })}
            placeholder="add something in the database"
            style={{ width: '200px' }}
          />
          <button onClick={() => this.putDataToDB(this.state.message)}>
            ADD
          </button>
        </div>
        <div style={{ padding: '10px' }}>
          <input
            type="text"
            style={{ width: '200px' }}
            onChange={(e) => this.setState({ idToDelete: e.target.value })}
            placeholder="put id of item to delete here"
          />
          <button onClick={() => this.deleteFromDB(this.state.idToDelete)}>
            DELETE
          </button>
        </div>
        <div style={{ padding: '10px' }}>
          <input
            type="text"
            style={{ width: '200px' }}
            onChange={(e) => this.setState({ idToUpdate: e.target.value })}
            placeholder="id of item to update here"
          />
          <input
            type="text"
            style={{ width: '200px' }}
            onChange={(e) => this.setState({ updateToApply: e.target.value })}
            placeholder="put new value of the item here"
          />
          <button
            onClick={() =>
              this.updateDB(this.state.idToUpdate, this.state.updateToApply)
            }
          >
            UPDATE
          </button>
          

         // Source: https://memorynotfound.com/dynamically-add-remove-options-select-javascript<br></br>-->
        <select id="dynamic-select">
                <option value="1">one</option>
                <option value="2">two</option>
                <option value="3">three</option>
        </select>

        {/*<button onClick={this.getOption()}>get item</button>*/}
        <button onClick={this.addOption}>add item</button> // remove the brackets to make it happen at onclick
        {/*<button type="button" onClick={this.addOption}>Go</button>
        <button onClick={this.removeOption()}>remove item</button>
        <button onClick={this.removeAllOptions}>remove all</button>*/}
        
        
        <br></br>
        {/*//option 10
        // source: https://stackoverflow.com/questions/27834226/add-event-listener-to-collection-of-html-elements*/}
        <input class="inputs" type="submit" value="Hello" />
        
                
        </div>
      </div>
    );
  }
}

export default App;
3
  • 1
    I doubt if someone would read this whole question. Keep it short and simple and add only the code that's really needed to fix the issue. Commented Nov 15, 2019 at 19:13
  • @KaleshKaladharan thank you for your suggestion, I removed the server.js running in the backend. Commented Nov 15, 2019 at 19:27
  • Your feedback was spot on, by simplifying and structuring/separating my attempts, and trying a single one more thorough, I was able to remove two erros in JSX formatting, the function call was in quotation marks, whereas it should be in curly brackets. That led to a key functionality required to answer the question: the ability to modify a dropdownbox in the express framework based on a click on the dropdownbox. I included the simplified app.js of with this functionality and removed the remainder attempts. Commented Nov 16, 2019 at 15:28

1 Answer 1

1
+50

Not sure why you need two different databases, I think two collections in one database is more fit, as in this case you can load all data required with aggregation. But then, how you formulated it, you have state with cars and colors, hide second dropdown of colors first, then on mount you already retrieving cars. After cars chosen, you make request to retrieve colors of given car and put it to state, which then make second dropdown appear.

getCars = async (carId) => {
  try {
    const carsResponse = await fetch(url, { method: 'POST', body: carId });
    const cars = await carsResponse.json();
    this.setState({ cars });
  } catch (err) {
    console.error(err);
  }
}

getColors = () => {
  // pretty same here
}

render () {
  return (
    <ul>
      {this.state.cars.map((car) => {
        return (
           <li key={car.id} onClick={() => this.getColors(car.id)}>car.name</li>
        );
      })}
    </ul>
    {this.state.colors.length > 0 && 
      <ul>
        {this.state.colors.map((color) => {
          <li key={color.id}>color.name</li>
        })}
      </ul>
    }

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

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.