SWETA SWAIN
SWETA SWAIN

Reputation: 69

Populate the drop-down menu based on previous selection in Flask python without using ajax?

I have a csv file in the form of dataframe which consist of location, Device and unit. Locations may be repeated locations with different units and devices.

I want 4 dropdown menu with

And a submit button, which displays all the selected fields.

On selection of location, it should display all unique locations based on the selection of location like PA, select unit will display like

Unit

    >:LAN
    >:WAN

Subunit

    >. LAN Switch
    >. WAN switch

Device

    > D2
    > D4

This is a example of the problem statement. Original file consist thousand locations and related units.

> Location   Device  Unit
> USA         D1     LAN core
> PA          D2     LAN Switch
> BLR         D3     LAN core
> PA          D4     WAN switch
> MEL         D5     DC metro

app.py:

from flask import Flask, render_template, request
    import pandas as pd
    app = Flask(__name__)
    app.debug = True

    @app.route('/', methods=['GET'])
    def dropdown():
        total_data = pd.read_csv("CPS.csv")
        print(total_data)
        data = total_data['LOCATION'].unique()
        print(data)

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

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

index.html

<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Dropdown</title>
    </head>
    <body>
      <select name= data  method="GET" action="/">
        {% for row in data %}
        <option value= "{{row}}" SELECTED>{{row}}</option>"
        {% endfor %}
      </select>
    </body>
  </html>

Upvotes: 3

Views: 3007

Answers (1)

Tobin
Tobin

Reputation: 2149

If you want to avoid going through an ajax request then you should consider registering your datas on the client side, by using technologies such as IndexedDB.

But if you want to keep your information on the server side, and access it dynamically, here's how you can implement that:

from flask_wtf import FlaskForm
from wtforms import SelectField
from flask import Flask, render_template, request, jsonify
import pandas as pd

class LocationsForm(FlaskForm):
    locations = SelectField('Locations')

@app.route('/', methods=['GET', 'POST'])
def dropdown():
    total_data = pd.read_csv("CPS.csv")
    data = total_data['LOCATION'].unique().tolist()

    form = LocationsForm()
    form.locations.choices = [(i, i) for i in data]

    return render_template(form=form)


@app.route('/device_choice/<value>')
def device_choice(value):
    location_choosen = value
    df = pd.read_csv("CPS.csv")
    df = df.set_index(["LOCATION"])
    df1 = df.loc[location_choosen, 'Device'].tolist()

    return jsonify({'Devices': df1})

@app.route('/unit_choice/<value>')
def unit_choice(value):
    # YOU CAN IMPLEMENT THIS BY FOLLOWING THE SAME MODEL AS THE DEVICES

I create a form that I populate dynamically with the values ​​of the locations only. then I render the form.

In my JS script I put an event that is triggered whenever there is a change in the field of locations.

At each change I send the selected value (location) to the device_choice route and find all the devices associated with this location. I return the devices as a list and fill in the appropriate selectfield (devices)

HTML's SIDE

<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Dropdown</title>
    </head>
    <body>
      {{ form.hidden_tag() }}
      {{ form.locations(class_="form-control") }}
      <select class="form-control devices" id="devices"></select>
      <select class="form-control unit" id="unit"></select>
    </body>
    <script>
        let location = document.getElementById('locations');
        let devices = document.getElementById('devices');

        location.onchange = function(){
            value = location.value;

            fetch('/device_choice/' + value).then(function(response){

                response.json().then(function(data){
                    let optionHTML = '';

                    for(let opt of data.Devices){
                        optionHTML += '<option value ="'  + opt + '">' + opt + '</option>';
                    }

                    devices.innerHTML = optionHTML;

                });
            });
        }
  </script>
  </html>

You just have to apply the same logic for the units too...

Upvotes: 5

Related Questions