AngularJS con Django - Tag modello in conflitto


302

Voglio usare AngularJS con Django, ma entrambi usano {{ }}come tag template. C'è un modo semplice per cambiare uno dei due per usare qualche altro tag di template personalizzato?


1
Rendo solo un modello dalla templatesdirectory di django , il resto l'ho inserito static. In questo modo non hai interferenze. C'è un tutorial che ho scritto qui: coderwall.com/p/bzjuka/…
Connor Leech,

come passare i dati tra angular2 e jinja2? Qualsiasi aiuto
Narendra,

@Narendra questo è un problema diverso non rilevante per questa domanda. Si prega di cercarlo e se non si trova una risposta, porre come una nuova domanda.
Endofago

Risposte:


299

Per Angular 1.0 è necessario utilizzare le API $ interpolateProvider per configurare i simboli di interpolazione: http://docs.angularjs.org/api/ng.$interpolateProvider .

Qualcosa del genere dovrebbe fare il trucco:

myModule.config(function($interpolateProvider) {
  $interpolateProvider.startSymbol('{[{');
  $interpolateProvider.endSymbol('}]}');
});

Tieni a mente due cose:

  • mescolare modelli lato server e lato client raramente è una buona idea e dovrebbe essere usato con cautela. I problemi principali sono: manutenibilità (difficile da leggere) e sicurezza (la doppia interpolazione potrebbe esporre un nuovo vettore di sicurezza - ad esempio, mentre la fuga del lato server e il modello lato client da soli potrebbero essere sicuri, la loro combinazione potrebbe non esserlo).
  • se inizi a utilizzare direttive (componenti) di terze parti che utilizzano {{ }}nei loro modelli, la tua configurazione le interromperà. ( correzione in sospeso )

Sebbene non ci sia nulla che possiamo fare per il primo problema, ad eccezione degli avvertitori, dobbiamo affrontare il secondo problema.


4
Ti dispiacerebbe spiegare il tuo primo punto (manutenzione, sicurezza e altre preoccupazioni per la combinazione di modelli lato server e lato client)? Una spiegazione in più sarebbe utile.
Brian

1
@btlachance - Ho ampliato la risposta.
Igor Minar,

12
Poiché $ interpolateProvider restituisce self quando viene utilizzato come setter, ecco una versione leggermente più compatta: $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
Mark Rajcok,

5
Sembra che la "correzione" sia chiusa. Ciò significa che ora non è sicuro utilizzare componenti di terze parti?
Alex Okrushko,

1
un modo per aggiornare anche $ interpolateProvider per l'output non elaborato? ad es. {{{foo}}} diventando {{[{foo}]}}?
tester

122

puoi forse provare il tag template integrale di Django e usarlo in questo modo:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>

{% verbatim %}
<div ng-app="">
    <p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}


Anche se questa è una soluzione molto valida, ci sono casi in cui voglio essere in grado di avviare il bootstrap delle mie viste con i dati dal server in modo da ottenere un disastro veloce. Pensa a cose come il nome utente dell'utente, non cambierà, quindi lo scriverò nel modello sul server, ma potrebbero esserci dei pezzi attorno ai quali scriverò con angolare.
Endofago

16
Verbatim fa parte dei tag core di Django dalla versione 1.5: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Pratyush,

11
In Django 1.7 non è necessario caricare testualmente poiché si trova nella libreria di tag standard. Hai solo bisogno di usare i tag stessi.
highpost il

1
Sarebbe bello avere un modo per cambiare le parentesi predefinite di Django dalle impostazioni, ma anche questo funziona.
Adrian Lopez,

42

Se le sezioni della pagina sono state separate correttamente, è possibile utilizzare facilmente i tag angularjs nell'ambito di tag "raw".

In jinja2

{% raw %}
    // here you can write angularjs template tags.
{% endraw %}

Nel modello Django (sopra 1.5)

{% verbatim %}    
    // here you can write angularjs template tags.
{% endverbatim %}

1
Questa soluzione non rompe la compatibilità con i pacchetti esterni come la risposta accettata.
partizanos,

30

Abbiamo creato un filtro molto semplice in Django 'ng' che semplifica il mix dei due:

foo.html:

...
<div>
  {{ django_context_var }}
  {{ 'angularScopeVar' | ng }}
  {{ 'angularScopeFunction()' | ng }}
</div>
...

Il ngfiltro è simile al seguente:

from django import template
from django.utils import safestring

register = template.Library()


@register.filter(name='ng')
def Angularify(value):
  return safestring.mark_safe('{{%s}}' % value)

Un altro modo molto valido per farlo, tuttavia preferirei cambiare i tag in un posto piuttosto che aggiungere il filtro in molti ...
Endofago

1
Come si crea il filtro ng? Puoi aggiungere un esempio?
Ben Liyanage,

Risposta aggiornata. @Endophage Ho molte più coppie angolari {{}} di quante ne abbia Django {{}}, quindi preferirei aggiornare quelle Django.
Wes Alvaro,

@WesAlvaro purtroppo posso solo accettare una risposta.
Endofago

26

Quindi ho ricevuto un grande aiuto nel canale IRC angolare oggi. Si scopre che puoi cambiare facilmente i tag dei template di Angular. I frammenti necessari di seguito devono essere inclusi dopo l'inclusione angolare (l'esempio dato viene visualizzato nelle loro mailing list e verrà utilizzato (())come nuovo tag modello, in sostituzione del proprio):

angular.markup('(())', function(text, textNode, parentElement){
  if (parentElement[0].nodeName.toLowerCase() == 'script') return;
  text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
  textNode.text(text);
  return angular.markup('{{}}').call(this, text, textNode, parentElement);
});

angular.attrMarkup('(())', function(value, name, element){
    value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
    element[0].setAttribute(name, value);
    return angular.attrMarkup('{{}}').call(this, value, name, element);
});

Inoltre, sono stato indicato un miglioramento imminente che esporrà startSymbole le endSymbolproprietà che possono essere impostate su qualsiasi tag desiderato.


17
e questo è come lo fai in angularjs 1.0: var m = angular.module ('myApp', []); m.config (function ($ interpolateProvider) {$ interpolateProvider.startSymbol ('(('); $ interpolateProvider.endSymbol ('))');});
idursun

Canale IRC angolare. A prima vista, ho trovato uno a #angularjs
Shanimal,

17

Voto contro l'uso delle doppie parentesi (()) come tag modello. Può funzionare bene fino a quando non è coinvolta alcuna chiamata di funzione ma quando viene provato quanto segue

ng:disabled=(($invalidWidgets.visible()))

con Firefox (10.0.2) su Mac ho ricevuto un errore terribilmente lungo invece della logica voluta. <[]> è andato bene per me, almeno fino ad ora.

Modifica 29/03/2012: si noti che $ invalidWidgets è obsoleto. Comunque userei ancora un altro involucro rispetto alle doppie parentesi graffe. Per qualsiasi versione angolare superiore a 0.10.7 (suppongo) potresti cambiare il wrapper molto più facilmente nella definizione della tua app / modulo:

angular.module('YourAppName', [], function ($interpolateProvider) {
    $interpolateProvider.startSymbol('<[');
    $interpolateProvider.endSymbol(']>');
}); 

Documenti API .


Punto valido. Non ci avevo pensato, ma non stavo particolarmente sostenendo l'uso (()), volevo solo essere in grado di configurare i delimitatori.
Endofago

15

Ho trovato utile il codice qui sotto. Ho trovato il codice qui: http://djangosnippets.org/snippets/2787/

"""
filename: angularjs.py

Usage:
    {% ng Some.angular.scope.content %}

e.g.
    {% load angularjs %}
    <div ng-init="yourName = 'foobar'">
        <p>{% ng yourName %}</p>
    </div>
"""

from django import template

register = template.Library()

class AngularJS(template.Node):
    def __init__(self, bits):
        self.ng = bits

    def render(self, ctx):
        return "{{%s}}" % " ".join(self.ng[1:])

def do_angular(parser, token):
    bits = token.split_contents()
    return AngularJS(bits)

register.tag('ng', do_angular)

Ho usato questo tag personalizzato ma poi se uso qualcosa del tipo: <p>{% ng location %}</p> viene reso come {{location}}- sì con parentesi graffe! Non rende il valore di $ scope.location che è codificato nel mio controller. Qualche idea di cosa mi sto perdendo?
Keshav Agrawal,


11

Se usi django 1.5 e versioni successive usa:

  {% verbatim %}
    {{if dying}}Still alive.{{/if}}
  {% endverbatim %}

Se sei bloccato con django 1.2 su appengine estendi la sintassi di django con il comando modello testuale come questo ...

from django import template

register = template.Library()

class VerbatimNode(template.Node):

    def __init__(self, text):
        self.text = text

    def render(self, context):
        return self.text

@register.tag
def verbatim(parser, token):
    text = []
    while 1:
        token = parser.tokens.pop(0)
        if token.contents == 'endverbatim':
            break
        if token.token_type == template.TOKEN_VAR:
            text.append('{{')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('{%')
        text.append(token.contents)
        if token.token_type == template.TOKEN_VAR:
            text.append('}}')
        elif token.token_type == template.TOKEN_BLOCK:
            text.append('%}')
    return VerbatimNode(''.join(text))

Nel tuo file usa:

from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')

Fonte: http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html


Grazie ... finalmente ho funzionato ma ho dovuto ... 1) creare un nuovo modulo Python. L'ho chiamato utilties e ho inserito il file verbatim_templatetag.py. (Il file sopra con la classe VerbatimNode definita in esso). 2) Cambia la dichiarazione di importazione da: from django import template a: from google.appengine._internal.django import template Quindi, nel mio file principale, ho appena cambiato il nome del file: template.register_template_library('utilities.verbatim_template_tag')
Roger

7

Puoi dire a Django di produrre {{e }}, così come altre stringhe di template riservate, usando il {% templatetag %}tag.

Ad esempio, usando {% templatetag openvariable %}sarebbe output {{.


3
So che è possibile ma è disordinato ... Sarebbe molto più pulito (e non sembra una domanda troppo grande) che il tag template sia semplicemente configurabile in uno dei framework. Alla fine della giornata sta solo eseguendo la corrispondenza delle stringhe dietro le quinte ...
Endofago il

3

Vorrei attenermi a una soluzione che utilizza sia i tag django {{}} che gli angularjs {{}} con una sezione testuale o templatetag.

Questo semplicemente perché puoi cambiare il modo in cui angularjs funziona (come detto) tramite $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol ma se inizi a utilizzare altri componenti angularjs come ui-bootstrap scoprirai che alcuni dei modelli sono GIÀ costruiti con tag angularjs standard {{}}.

Ad esempio, guarda https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html .


Buon punto. Ora c'è un pacchetto django-angolare in PyPI che ha lo scopo di rendere i due giochi piacevoli insieme, ma non ho esaminato quanto allevia il problema del tag template.
Endofago il

0

Se si esegue un'interpolazione sul lato server, l' unico modo corretto per farlo è con<>

$interpolateProvider.startSymbol('<{').endSymbol('}>');

Qualsiasi altra cosa è un vettore XSS.

Questo perché eventuali delimitatori angolari che non sfuggono a Django possono essere inseriti dall'utente nella stringa interpolata; se qualcuno imposta il suo nome utente su "{{evil_code}}", Angular lo eseguirà felicemente . Se usi un personaggio di cui Django sfugge , tuttavia, questo non accadrà.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.