Как передать список из Python, Jinja2 на JavaScript

Я новичок в JavaScript, и сейчас я имею дело с проблемой. Скажем, у меня есть переменная Python:

listOfItems= ['1','2','3','4','5']

и я передаю его Jinja путем рендеринга HTML, и у меня также есть функция в JavaScript под названием somefunction(variable). Я пытаюсь передать каждый элемент "listOfItems". Я пробовал что-то вроде этого:

{% for item in listOfItems %}<br>
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}

Можно ли передать список из Python на JavaScript или я должен передать каждый элемент из списка один за другим в цикле? Как я могу это сделать?

Ответ 1

Чтобы передать некоторые данные контекста в javascript-код, вы должны сериализовать его так, чтобы он был "понят" javascript (а именно JSON). Вы также должны пометить его как безопасное с помощью фильтра safe Jinja, чтобы ваши данные не были htmlescaped.

Вы можете добиться этого, сделав что-то вроде этого:

Вид

import json

@app.route('/')
def my_view():
    data = [1, 'foo']
    return render_template('index.html', data=json.dumps(data))

Шаблон

<script type="text/javascript">
    function test_func(data) {
        console.log(data);
    }
    test_func({{ data|safe }})
</script>

Изменить - точный ответ

Итак, чтобы добиться именно того, что вы хотите (перебирайте список элементов и передавайте их в функцию javascript), вам нужно будет сериализовать каждый элемент в вашем списке отдельно. Тогда ваш код будет выглядеть так:

Вид

import json

@app.route('/')
def my_view():
    data = [1, "foo"]
    return render_template('index.html', data=map(json.dumps, data))

Шаблон

{% for item in data %}
    <span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}

Изменить 2

В моем примере я использую Flask, я не знаю, какую инфраструктуру вы используете, но вы поняли, что вам просто нужно, чтобы она соответствовала используемой структуре.

Редактировать 3 (Предупреждение о безопасности)

НИКОГДА НЕ СОХРАНЯЙТЕ ЭТО С ПОСТАВЩИМИ ПОЛЬЗОВАТЕЛЕМ, ТОЛЬКО СДЕЛАЙТЕ ЭТО С ДОВЕРЕННЫМИ ДАННЫМИ!

В противном случае вы можете подвергнуть ваше приложение уязвимостям XSS!

Ответ 2

У меня была аналогичная проблема с использованием Flask, но мне не пришлось прибегать к JSON. Я просто передал список letters = ['a','b','c'] с помощью render_template('show_entries.html', letters=letters) и установил

var letters = {{ letters|safe }}

в моем javascript-коде. Jinja2 заменил {{ letters }} на ['a','b','c'], который javascript интерпретируется как массив строк.

Ответ 3

Я могу предложить вам подход, ориентированный на JavaScript, который упрощает работу с файлами javascript в вашем проекте.

Создайте раздел javascript в файле шаблона jinja и поместите все переменные, которые вы хотите использовать в ваших файлах javascript, в объекте window:

start.html

...
{% block scripts %}
<script type="text/javascript">
window.appConfig = {
    debug: {% if env == 'development' %}true{% else %}false{% endif %},
    facebook_app_id: {{ facebook_app_id }},
    accountkit_api_version: '{{ accountkit_api_version }}',
    csrf_token: '{{ csrf_token }}'
}
</script>
<script type="text/javascript" src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}

Jinja заменит значения, и наш объект appConfig будет доступен из наших других файлов script:

App.js

var AccountKit_OnInteractive = function(){
    AccountKit.init({
        appId: appConfig.facebook_app_id,
        debug: appConfig.debug,
        state: appConfig.csrf_token,
        version: appConfig.accountkit_api_version
    })
}

Я отделил код javascript от html-документов таким образом, который проще в управлении и дружелюбен.