-1

I have a simple but frustrating problem.

On the backend, I have a 2d list being passed from python over to the frontend with jinja. I then want to iterate over this array using a for loop, but I can't pass the variable from that for loop into the jinja array because it won't recognize it.

For example (this is taken from a larger function):

for (let i = 0; i < {{rows}}; i++) {
 clone.getElementById("name").innerHTML = "{{data[i+1][0]}}";
}

Jinja has no idea what "i" is. Is there a way to pass that variable into jinja?

Benjbear
  • 9
  • 1
  • 1
    Just remember at what point Jinja and JS are running. One runs on the server and the other later on the client. – Klaus D. Jun 29 '22 at 19:45
  • @RobinZigmond I think I grasp the reasoning for things not working, but not how to fix them! – Benjbear Jun 29 '22 at 20:39
  • @Benjbear - it's hard to say what the best way to fix it because that depends on your exact purposes: but if you absolutely need to get the server to do something based on a Javascript variable, you'll have to make an Ajax request and write a new backend page/endpoint to handle it. – Robin Zigmond Jun 29 '22 at 20:53

1 Answers1

0

As previous speakers have explained, there is a difference in execution time between a jinja template and the JavaScript code.

However, you can pass data to JavaScript inside jinja. The solution is the tojson filter, which allows you to serialize a python variable to json and then assign it to a variable in JavaScript. It is then possible, for example, to iterate over a resulting array, as in the following example.

from flask import (
    Flask,
    render_template
)

app = Flask(__name__)

@app.route('/')
def index():
    data = [
        ['one', 'more', 'thing'],
        ['some', 'thing', 'else']
    ]
    return render_template('index.html', **locals())
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Index</title>
  </head>
  <body>

    <script type="text/javascript">
      (function(data) {
        data.forEach(row => {
          console.log(row[0]);
        });
      })({{data|tojson}});
    </script>

  </body>
</html>

If you want to send data from JavaScript to the server for processing in python, send an AJAX request.

from flask import (
    Flask,
    jsonify, 
    render_template,
    request
)

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', **locals())

@app.post('/recieve')
def recieve():
    data = request.json
    print(data)
    return jsonify(success=True)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Index</title>
  </head>
  <body>

    <script type="text/javascript">
        (function(url) {
          const data = [
            ['one', 'more', 'thing'],
            ['some', 'thing', 'else']
          ];
          fetch(url, {
            method: 'post',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
          }).then(resp => resp.json())
            .then(data => console.log(data));
        })({{url_for('recieve')|tojson}})
    </script>

  </body>
</html>
Detlef
  • 6,137
  • 2
  • 6
  • 24
  • I see - I think I grasp how the execution times are coming in to play, but I feel a bit over my head here now. It might help to summarize what I'm trying to do. I have a google sheets with data, and all I want to do is take that data, and depending on how many rows there are, create that many tables on my html page. On the page, you will be able to delete these tables, which will also delete the row in sheets. I think I see how I need to use tjson to transfer the data over. I'm not sure how that code gives me an array I can then work with in js however. – Benjbear Jun 29 '22 at 20:39
  • It's just important to know that jinja runs on the server and javascript runs on the client. In the example, the Python list is converted into a JavaScript array and passed as a parameter to a directly executed anonymous function. However, you can also assign the array to a variable if you prefer. It makes no difference. The tojson filter gives you the possibility to pass data to JavaScript within a jinja template. A list becomes an array, a dict becomes an object, and so on. If you need further explanations leave me a comment. At the moment I'm not sure how to help you. – Detlef Jun 29 '22 at 21:03
  • 1
    I think for your tables you can generate the corresponding HTML code with jinja. For deleting, as @RobinZingmond explains, you should send an AJAX request to another endpoint/route. This is the common way to send data from JavaScript back to the python server. – Detlef Jun 29 '22 at 21:16