web-dev-qa-db-fra.com

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 HTML, et j'ai aussi une fonction en JavaScript appelée somefunction(variable). J'essaie de transmettre 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 en boucle? Comment puis-je faire ceci?

52
user1843766

Pour transmettre des données de contexte au code javascript, vous devez le sérialiser de manière à ce qu'il soit "compris" par javascript (à savoir JSON). Vous devez également le marquer comme étant sûr à l’aide du filtre safe Jinja, afin d’empêcher que vos données ne soient encapsulées.

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 gabarit

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

Edit - réponse exacte

Ainsi, pour obtenir exactement ce que vous voulez (passer en boucle 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 gabarit

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

Modifier 2

Dans mon exemple, j'utilise Flask, je ne sais pas quel framework vous utilisez, mais vous avez eu l'idée, il vous suffit de l'adapter au framework que vous utilisez.

Edit 3 (Avertissement de sécurité)

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

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

80
mdeous

J'ai eu un problème similaire en utilisant Flask, mais je n'ai pas eu à recourir à JSON. Je viens de passer 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 a remplacé {{ letters }} par ['a','b','c'], code javascript interprété comme un tableau de chaînes.

24
Godsmith

Pour ajouter la réponse sélectionnée, j'ai testé une nouvelle option qui fonctionne également avec jinja2 et flask:

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

Le gabarit:

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

la sortie du modèle rendu:

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

La safe pourrait être ajoutée mais ressemblerait aussi à {{ data | tojson | safe }} mais cela fonctionnerait aussi.

0
Sylhare

Je peux vous suggérer une approche orientée javascript qui facilite le travail avec les fichiers javascript dans votre projet.

Créez une section javascript dans votre fichier de modèle jinja et placez toutes les variables que vous souhaitez utiliser dans vos fichiers javascript dans un objet 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 remplacera les valeurs et notre objet appConfig sera accessible à partir de nos autres fichiers de 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 convivial.

0
muratgozel

Vous pouvez le faire avec le filtre tojson de Jinja, qui

Transforme une structure en JSON de manière à pouvoir l’utiliser en toute sécurité dans les balises <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 noeud final Flask:

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

Ensuite, dans votre modèle, écrivez ceci:

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

(Notez que l'attribut onclick est single -quoted. Ceci est nécessaire car |tojson échappe des caractères ' mais pas des caractères " dans sa sortie, ce qui signifie qu'il peut être utilisé en toute sécurité dans les attributs HTML à guillemets simples, mais pas les 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 encoder des variables JSON dans votre code Python et transmettez le texte JSON résultant à votre modèle. Cela produira une sortie incorrecte pour certaines valeurs de chaîne et vous exposera à XSS si vous essayez de coder des valeurs fournies par l'utilisateur. Ceci est dû au fait que le json.dumps intégré de Python n'échappe pas aux caractères tels que < et > (qui doivent échapper aux valeurs de modèle en toute sécurité dans les <script>s en ligne, comme indiqué à https://html.spec.whatwg.org/multipage/scripting. html # restrictions-pour-contenus-d'éléments-de-script ) ou guillemets simples (qui doivent être échappés pour modéliser en toute sécurité des valeurs dans des attributs HTML entre guillemets simples).

Si vous utilisez Flask, notez que Flask injecte un filtre tojson personnalisé au lieu d'utiliser la version de Jinja. Cependant, tout ce qui est écrit ci-dessus s'applique toujours. Les deux versions se comportent presque à l'identique; Flask's juste permet une configuration spécifique à l'application qui n'est pas disponible dans la version de Jinja.

0
Mark Amery