1

My goal is an interactive html with a Python-code on the backend. In the basis, the html-page will contain a couple of sliders, and their values will be used as input for a Python-based code to returns some value(s) back to the html-page to present.

Nothing fancy, I thought. However... I want that the value of the slider is send to the Python-code immediately, and the Python-code "immediately" sends back its output ("immediately" = ASAP). For some reason, I get one of the following two working, but not both:

  1. The slider's value is updated immediately and its value is presented on screen. Simultaneously, I can see that the correct Python-method is called, but no data is transferred.
  2. The slider's value is submitted to the Python-code and its output is returned to the html-page, but it requires a click on a submit-button.

MWE:

html-page:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Estimate</title>
</head>
<body>
    <form method="POST">
        <div class="rangeslider">
            <input type="range" name="var1" min="0" max="10" value="5" class="myslider" id="slider1">
            <p>
                Var. 1: <span id="out1"></span>
            </p>
        </div>

        <script>
            const Http = new XMLHttpRequest();
            var slide1 = document.getElementById("slider1");
            var out1 = document.getElementById("out1");

            slider1.oninput = function() {
                out1.innerHTML = this.value;

                Http.open('POST', '/output')
                Http.send(out1)
            }
        </script>
    </form>
</body>
</html>

Python-backend:

from flask import Flask, render_template, request

app = Flask(__name__)


@app.route('/')
def base():
    return render_template('estimate.html', var1=5)


@app.route('/output', methods=['POST'])
def update():
    # var1 = request.form['var1']
    data = request.form  # results in an empty dict: `ImmutableMultiDict([])`
    var1 = 5  # so the return-statement does not break
    print(data)  # I know that this method is called, as `data` (empty dict) is printed when I change the sliders value
    return render_template('estimate.html', var1=var1, output=f'Output\nVariable 1 = {var1}')


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

I do know about the option of onchange in the html-slider, but have not got it working.

I am quiet new to html and do not know much about JavaScript; I am more familiar with Python.

Hopefully anyone can help me out! I have searched around quiet a lot already, but have not found an answer to my issue.

If it matters: I am using Python 3.7, and use flask as framework.

3 Answers 3

1

Turbo Flask is what you need.

(venv) $ pip install flask turbo-flask

Github link here.

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

Comments

0
  1. I think it makes sense to call your server when the slide value changes (onchange event). See this Stackoverflow answer on how to use a slider's onchange event.

  2. In your python code, you are doing request.form['var1'] but you did not post your form (per your code, you only sent a specific variable). I think you have the following options

    a. Send the entire form. See MDN documentation for different ways you can do this

    b. Send just the data for the input field. To do this, you'll have to create a parameter for it. Something like

    var params = {"var1" : document.getElementById("out1").value};
    
    // Send the param
    HTTP.send(params)
    
    # Receive it in your python code as
    request.values.get("var1")
    
    
  3. If you're sending just a single variable and it is not of a large size and you are doing an asynchronous call (which means user never sees your url on their browser), you can actually make this a GET call and not a POST call

Comments

0

Use fetch requests, to perform ajax requests without using a form submit.

Following into your html, remove rangeslider out of the form body and change script to this:

<div class="rangeslider">
        <input type="range" name="var1" min="0" max="10" value="5" class="myslider" id="slider1">
        <p>
            Var. 1: <span id="out1"></span>
        </p>
    </div>

    <script>

      var slide1 = document.getElementById("slider1");
      var out1 = document.getElementById("out1");

      slider1.oninput = function() {
        fetch('/slider/'+this.value).then(function(response){
          response.json().then(function(data){
          out1.innerHTML = data.value
          })
        })
      }
  </script>

Then in your back-end, add this to your routes

@app.route('/slider/<value>',methods = ['GET','POST'])
def slider(value):
    return jsonify({'value': value})

P.S you will need Jquery to perform ajax requests, so add it to your HTML head

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.