3

I have 3 dropdown, the values filled dynamically with mysql. Now, I'm trying to cascade the 3 dropdown, but JS script is not working.

What I'm trying to do's:

Case 1: If the user choose a value from dropdown #1, the value of dropdown #2 depends on dropdown #1, the value of dropdown #3 depends on dropdown #2. E.g. State - City - Avenue

Case 2: The user can choose from 3 dropdown.

Case 3 and 4: If the user choose from dropdown #2, the values of dropdown #3 depends in dropdown #2 (but choosing a value in dropdown #3 is optional, if the dropdown #2 have already)

Form:

<form action='' method='post' id='loc'>
<select name="state" id="filter_region" class="state">
    <option name="default" class="default" value="State" readonly>State</option>
    <?php
    foreach($result_state as $option){
        if(isset($_POST['state']) && $_POST['state'] == $option->state)
            echo '<option name="state" class="filter_by" selected value="'. $option->state .'">'. $option->state .'</option>';
        else    
         echo '<option name="state" class="filter_by" value="'. $option->state .'">'. $option->state .'</option>';
     };
    ?>
</select>

<select name="city" id="filter_city" class="city">
    <option name="default" class="default" value="City" readonly>City</option>
    <?php
    foreach($result_city as $option){
        if(isset($_POST['city']) && $_POST['city'] == $option->city)
            echo '<option name="city" class="filter_by" selected value="'. $option->city .'">'. $option->city .'</option>';
        else    
         echo '<option name="city" class="filter_by" value="'. $option->city .'">'. $option->city .'</option>';
     };
    ?>
</select>
<select name="avenue" id="filter_mall" class="avenue">
    <option name="default" class="default" value="Avenue" readonly>Avenue</option>
    <?php 
    foreach($result_avenue as $option){
        if(isset($_POST['avenue']) && $_POST['avenue'] == $option->avenue)
            echo '<option name="avenue" class="default" selected value="'. $option->avenue .'">'. $option->avenue .'</option>';
        else    
         echo '<option name="avenue" class="filter_by" value="'. $option->avenue .'">'. $option->avenue .'</option>';
     };
    ?>
</select>
<input type="submit" value="submit" class="submit"/>
</form>

JS:

function cascadeSelect(parent, child){
    var childOptions = child.find('option:not(.default)');
    child.data('options',childOptions);

    parent.change(function(){
        childOptions.remove();
        child
            .append(child.data('options').filter('.filter_by' + this.value))
            .change();
    })

    childOptions.not('.default, .filter_by' + parent.val()).remove();
}

$(function(){
    cascadeForm = $('.loc');
    state= cascadeForm.find('.state');
    city= cascadeForm.find('.city');
    avenue= cascadeForm.find('.avenue');

    cascadeSelect(state, city);
    cascadeSelect(city, avenue);
});

1 Answer 1

4
+50

I had created cascading parent-child select-boxes using AngularJS, but since you are using NativeJS, I tried to re-create using JS. The pre-requisite of my solution is a well-defined JSON based on which the select-boxes will be created. You'll have to create the JSON on server side or manually or wherever you are creating the select-box data. Below is the JSON format.:

Every select-box is a named object with following properties:

  1. Parent Attribute: Name of object which is the parent of this select-box object.
  2. Options: Array of option objects, where each object contains: (a) Option Value (b) Parent Option Value - The parent select-box value with which the current value is mapped. (c) Option ID.

  3. Selected Option: An object with two properties: (a) Currently selected value (b) ID of currently selected value.

enter image description here

Here is the working Plunker of the solution. Hope it helps.

----- EDIT: -----

On request of @User014019

Here is the another version of this drop-down solution where all the options in all select-boxes are visible initially, and parent-child relationships are set when user select a particular value.


Below is the code:

// reads the data and creates the DOM elements (select-boxes and their relevant options)
function initSelect(data) {
  var select, option, input, filteredOptions;
  for (var key in data) {
    select = document.createElement("select");
    select.name = key;
    container.appendChild(select);
    filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
    input = document.querySelector('select[name="' + key + '"');
    input.setAttribute("onchange", "updateSelect(this)");
    for (var i = 0; i < filteredOptions.length; i++) {
      option = document.createElement("option");
      option.value = filteredOptions[i].value;
      option.innerHTML = filteredOptions[i].value;
      input.appendChild(option);
    }
    input.options.selectedIndex = getSelectedIndex(filteredOptions, data[key]);
    input.setAttribute('model', data[key].selectedOption.value);
  }
}


// this function will be called on change of select-box
function updateSelect(element) {
  var input, option;
  setSelectedOption(element);
  for (var key in data) {
    filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
    input = document.querySelector('select[name="' + key + '"');
    while (input.firstChild) {
      input.removeChild(input.firstChild);
    }
    for (var i = 0; i < filteredOptions.length; i++) {
      option = document.createElement("option");
      option.value = filteredOptions[i].value;
      option.innerHTML = filteredOptions[i].value;
      input.appendChild(option);
    }
    input.options.selectedIndex = getSelectedIndex(filteredOptions, data[key]);
    input.setAttribute('model', data[key].selectedOption.value);
  }
}

// set the selected-option of select-box when it's changed
function setSelectedOption(element) {
  var inputName = element.getAttribute("name");
  var inputValue = getSelectedText(element);
  var inputItem = data[inputName];
  var selectedOption, filteredOptions;

  // setting selected option of changed select-box
  for (var i = 0; i < inputItem.availableOptions.length; i++) {
    if (inputValue === inputItem.availableOptions[i].value) {
      inputItem.selectedOption = inputItem.availableOptions[i];
      break;
    }
  }
  // setting child object selected option now
  for (var key in data) {
    if (data[key].parent === inputName) {
      filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
      data[key].selectedOption = filteredOptions[0];
    }
  }
}

// get the text of select-box
function getSelectedText(element) {
  if (element.selectedIndex == -1) {
    return null;
  }
  return element.options[element.selectedIndex].text;
}

function getSelectedIndex(options, self) {
  var index;
  for (var i = 0; i < options.length; i++) {
    if (self.selectedOption.value === options[i].value) {
      index = i;
      break;
    }
  }
  return index;
}

// get filtered options based on parent's selected value
function optionFilter(items, parent, self) {
  var result = [];
  if (typeof parent !== "undefined") {
    for (var i = 0; i < items.length; i++) {
      if (typeof parent.selectedOption !== "undefined") {
        if (parent.selectedOption !== null && items[i].parentValue === parent.selectedOption.value) {
          result.push(items[i]);
        }
      }
    }
    if (typeof self.selectedOption === "undefined") {
      self.selectedOption = null;
    }
    if (self.selectedOption === null) {
      self.selectedOption = result[0];
    }
    return result;
  } else {
    return items;
  }
}
Sign up to request clarification or add additional context in comments.

20 Comments

how can i use my existing template of dropdown with your js?
how to use the data from mysql?
The solution I posted is completely dependent on the data-structure I have used (explained in post). And the HTML generation is completely dynamic (no manual or static HTML code). You'll have to re-structure your complete code if you wish to use this solution. As for MySql, can you please elaborate you question a little bit more.
The data of each dropdown is fulfilled from mysql dbase. How can I call the data in function getData() if from mysql dbase?
How are you getting the MySql data in client-side currently? Are you using any middle layer?
|

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.