98 votes

Comment passer une liste de Python, par Jinja2 à JavaScript

Disons que j'ai une variable Python :

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

et je le passe à Jinja en rendant le HTML, et j'ai aussi une fonction en JavaScript appelée somefunction(variable) . J'essaie de faire passer chaque élément de list_of_items . J'ai essayé quelque chose comme ça :

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

Est-il possible de passer une liste de Python à JavaScript ou dois-je passer chaque élément de la liste un par un dans une boucle ? Comment puis-je faire cela ?

138voto

MatToufoutu Points 5879

Pour transmettre des données contextuelles au code javascript, vous devez les sérialiser de manière à ce qu'elles soient "comprises" par javascript (à savoir JSON). Vous devez également le marquer comme sûr à l'aide de la balise safe Filtre Jinja, pour éviter que vos données ne soient mises en forme par des htmlescapes.

Vous pouvez y parvenir en faisant quelque chose comme ça :

La vue

import json

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

Le modèle

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

Editer - réponse exacte

Ainsi, pour obtenir exactement ce que vous voulez (boucler sur une liste d'éléments et les transmettre à une fonction javascript), vous devez sérialiser chaque élément de votre liste séparément. Votre code ressemblerait alors à ceci :

La vue

import json

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

Le modèle

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

Edit 2

Dans mon exemple, j'utilise Flask Je ne sais pas quel cadre vous utilisez, mais vous avez l'idée, vous devez juste l'adapter au cadre que vous utilisez.

Edit 3 (Avertissement de sécurité)

NE FAITES JAMAIS CELA AVEC DES DONNÉES FOURNIES PAR L'UTILISATEUR, MAIS UNIQUEMENT AVEC DES DONNÉES DE CONFIANCE !

Sinon, vous exposeriez votre application à des vulnérabilités XSS !

39voto

Godsmith Points 334

J'ai eu un problème similaire en utilisant Flask, mais je n'ai pas eu à recourir à JSON. J'ai juste passé une liste letters = ['a','b','c'] avec render_template('show_entries.html', letters=letters) et définir

var letters = {{ letters|safe }}

dans mon code javascript. Jinja2 remplacé {{ letters }} avec ['a','b','c'] que javascript a interprété comme un tableau de chaînes de caractères.

25voto

Mark Amery Points 4705

Vous pouvez le faire avec l'outil Jinja tojson filtre, qui

Vide une structure en JSON afin qu'elle puisse être utilisée sans risque dans <script> et] à n'importe quel endroit du code HTML, à l'exception notable des attributs entre guillemets.

Par exemple, dans votre Python, écrivez :

some_template.render(list_of_items=list_of_items)

... ou, dans le contexte d'un endpoint Flask :

return render_template('your_template.html', list_of_items=list_of_items)

Puis dans votre modèle, écrivez ceci :

{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}

(Notez que le onclick L'attribut est simple -Citation. Ceci est nécessaire car |tojson s'échappe ' caractères mais pas " dans sa sortie, ce qui signifie qu'il peut être utilisé en toute sécurité dans les attributs HTML entre guillemets simples mais pas entre guillemets doubles).

Ou, pour utiliser list_of_items dans un script en ligne au lieu d'un attribut HTML, écrivez ceci :

<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>

N'utilisez pas json.dumps pour coder en JSON des variables dans votre code Python et transmettre le texte JSON résultant à votre modèle. Cela produira une sortie incorrecte pour certaines valeurs de chaîne et vous exposera à un XSS si vous essayez d'encoder des valeurs fournies par l'utilisateur. En effet, la fonction intégrée de Python json.dumps n'échappe pas les caractères comme < y > (qui ont besoin d'un échappement pour que les valeurs des modèles puissent être mises en ligne en toute sécurité). <script> comme indiqué à https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-éléments ) ou des guillemets simples (qui doivent être escamotés pour que les valeurs des modèles puissent être converties en attributs HTML à guillemets simples).

Si vous utilisez Flask, notez que Flask injecte un fichier personnalisé tojson au lieu d'utiliser la version de Jinja. Cependant, tout ce qui est écrit ci-dessus reste valable. Les deux versions se comportent de manière presque identique ; celle de Flask ne fait que permet une configuration spécifique de l'application qui n'est pas disponible dans la version de Jinja.

7voto

Sylhare Points 647

Pour compléter la réponse choisie, j'ai testé une nouvelle option qui fonctionne aussi en utilisant jinja2 et flask :

@app.route('/')
def my_view():
    data = [1, 2, 3, 4, 5]
    return render_template('index.html', data=data)

Le modèle :

<script>
    console.log( {{ data | tojson }} )
</script>

la sortie du modèle rendu :

<script>
    console.log( [1, 2, 3, 4] )
</script>

En safe pourrait être ajouté mais aussi comme {{ data | tojson | safe }} pour éviter l'échappement html mais cela fonctionne sans aussi.

2voto

muratgozel Points 549

Je peux vous suggérer une approche orientée javascript qui permet de travailler facilement avec des fichiers javascript dans votre projet.

Créez une section javascript dans votre fichier de modèle jinja et placez toutes les variables que vous voulez utiliser dans vos fichiers javascript dans un objet fenêtre :

Début.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 remplacera les valeurs et notre objet appConfig sera accessible à partir de nos autres fichiers 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
    })
}

J'ai séparé le code javascript des documents html de cette manière qui est plus facile à gérer et respectueuse de l'environnement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X