update the value of a drop down filter according to the entry of the first

Question:

I’m developing a flask application that filters the value of a Mysql database table and depending on the selected value of the first drop down it will update the value of the second drop down. and then finally return some data

now the code is working but there seems to be bug in the code, such that when i make a new selection from the first drop down it will populate the second drop down with the values of the first drop down together with the expected values of the second drop down

it should not do that i expected it to only populate the second drop down with the expected values and not add the values of the first drop down together with it.

this is my flask application code:

from flask import jsonify, request
from flask import Flask, render_template  
import mysql.connector

app = Flask(__name__)

# Configure MySQL connection
cnx = mysql.connector.connect(
  host="xxxxxxx",
  user="xxxxxxxxx",
  password="xxxxxxxxx",
  database="xxxxxxxxxx")


@app.route('/', methods=['GET', 'POST'])
def index():
    try:
        cursor = cnx.cursor()
        query = "SELECT topic FROM text_table"
        cursor.execute(query)
        data = [row[0] for row in cursor.fetchall()] # Get the first column of all rows
        cursor.nextset() # consume any unread result
        cursor.close()


        if request.method == 'POST':
            selected_topic = request.form.get('selected_topic') # Get the selected topic from the form
            if selected_topic:
                cursor = cnx.cursor()
                query = "SELECT sub_topic FROM text_table WHERE topic = %s"
                cursor.execute(query, (selected_topic,))
                sub_topics = [row[0] for row in cursor.fetchall()] # Get the sub topics for the selected topic
                cursor.nextset()
                selected_sub_topic = request.form.get('selected_sub_topic') # Get the selected sub topic from the form
                if selected_sub_topic:
                    query = "SELECT text FROM text_table WHERE topic = %s AND sub_topic = %s"
                    cursor.execute(query, (selected_topic, selected_sub_topic))
                    result = cursor.fetchone()[0] # Get the value of the text for the selected sub topic
                    cursor.nextset()
                    cursor.close()
                    return render_template('index.html', topics=data, selected_topic=selected_topic, sub_topics=sub_topics, selected_sub_topic=selected_sub_topic, result=result)

                cursor.close()
                return render_template('index.html', topics=data, selected_topic=selected_topic, sub_topics=sub_topics)

        return render_template('index.html', topics=data)

    except Exception as e:
        # Return an error message if there's an exception
        return jsonify(error=str(e)), 500


if __name__ == '__main__':
    app.run()

this is my html code with a little bit of javascript

<!DOCTYPE html>
<html>
  <head>
    <title>Drop Down Filter</title>
    <script>
        function updateSubTopics() {
            var selectTopic = document.getElementById("selected_topic");
            var selectSubTopic = document.getElementById("selected_sub_topic");
            var selectedTopicValue = selectTopic.value;

            // Send a POST request to update the sub topic options
            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/');
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.onload = function() {
                if (xhr.status === 200) {
                    // Update the sub topic options
                    selectSubTopic.innerHTML = xhr.responseText;

                    // Check if the currently selected sub topic is valid for the new selected topic
                    var subTopicOptions = selectSubTopic.options;
                    var foundSelectedSubTopic = false;
                    for (var i = 0; i < subTopicOptions.length; i++) {
                        if (subTopicOptions[i].value === selectSubTopic.value) {
                            foundSelectedSubTopic = true;
                            break;
                        }
                    }
                    if (!foundSelectedSubTopic) {
                        selectSubTopic.value = "";
                    }
                }
                else {
                    console.log('Request failed. Returned status of ' + xhr.status);
                }
            };
            xhr.send('selected_topic=' + selectedTopicValue);
        }
    </script>
  </head>
  <body>
    <form method="POST">
      <select name="selected_topic" id="selected_topic" onchange="updateSubTopics()">
        {% for topic in topics %}
          <option value="{{ topic }}"
            {% if selected_topic == topic %}selected{% endif %}>
            {{ topic }}
          </option>
        {% endfor %}
      </select>
      <select name="selected_sub_topic" id="selected_sub_topic">
        {% for sub_topic in sub_topics %}
          <option value="{{ sub_topic }}"
            {% if selected_sub_topic == sub_topic %}selected{% endif %}>
            {{ sub_topic }}
          </option>
        {% endfor %}
      </select>
      <input type="submit" value="Filter">
    </form>
    {% if result %}
      <h1>{{ result }}</h1>
    {% endif %}
  </body>
</html>

thank you, any help will be greatly appreciated

Asked By: ovu sunday

||

Answers:

The problem occurs when you are sending a template response after filtering.

return render_template(‘index.html’, topics=data, selected_topic=selected_topic, sub_topics=sub_topics)

You already have rendered index.html however you also are rendering index.html when the select option is changed from this line.

selectSubTopic.innerHTML = xhr.responseText;

What this basically means is that you are pasting all your html code inside select element which you can check by inspecting in your browser.

In my opinion, What should be done is that you should only send a python dictionary as a response for sub topics.

if selected_topic:
    cursor = cnx.cursor()
    query = "SELECT sub_topic FROM text_table WHERE topic = %s"
    cursor.execute(query, (selected_topic,))
    sub_topics = [row[0] for row in cursor.fetchall()] # Get the sub topics for the selected topic
    cursor.nextset()
    selected_sub_topic = request.form.get('selected_sub_topic') # Get the selected sub topic from the form
    if selected_sub_topic:
        query = "SELECT text FROM text_table WHERE topic = %s AND sub_topic = %s"
        cursor.execute(query, (selected_topic, selected_sub_topic))
        result = cursor.fetchone()[0] # Get the value of the text for the selected sub topic
        cursor.nextset()
        cursor.close()
        return render_template('index.html', topics=data, selected_topic=selected_topic, sub_topics=sub_topics, selected_sub_topic=selected_sub_topic, result=result)

        cursor.close()
        return sub_topics

After successfully getting the dictionary, the response will be in format so it needs to be parsed to json. Then you can use a JS loop to create loops and append it to your sub_topic select item.


if (xhr.status === 200) {
    selectSubTopic.options.length = 0;
    
    var subTopicOptions = JSON.parse(xhr.responseText);

    for (var i = 0; i < subTopicOptions.length; i++) {
        var option = document.createElement('option');
        option.text = subTopicOptions[i];
        option.value = subTopicOptions[i];
        selectSubTopic.appendChild(option);
    }
    
    // Check if the currently selected sub topic is valid for the new selected topic
    var subTopicOptions = selectSubTopic.options;
    var foundSelectedSubTopic = false;
    for (var i = 0; i < subTopicOptions.length; i++) {
        if (subTopicOptions[i].value === selectSubTopic.value) {
            foundSelectedSubTopic = true;
            break;
        }
    }
    if (!foundSelectedSubTopic) {
        selectSubTopic.value = "";
    }
}
else {
    console.log('Request failed. Returned status of ' + xhr.status);
}
Answered By: Sanjay Shahi
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.