AngularJS avec Django – étiquettes de modèle en conflit

Je veux utiliser AngularJS avec Django, mais ils utilisent tous deux {{ }} comme leurs balises de modèle. Existe-t-il un moyen simple de changer l'un des deux pour utiliser une autre étiquette de modèle personnalisée?

Pour Angular 1.0, vous devez utiliser les apis $ interpolateProvider pour configurer les symboles d'interpolation: http://docs.angularjs.org/api/ng.$interpolateProvider .

Quelque chose comme ça devrait faire l'affaire:

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

Gardez à l'esprit deux choses:

  • Le mélange des modèles côté client et côté client est rarement une bonne idée et devrait être utilisé avec prudence. Les principaux problèmes sont: la durabilité (difficile à lire) et la sécurité (une double interpolation pourrait exposer un nouveau vecteur de sécurité – par exemple, en cas d'échappement de serveurs et de gabarits clients, ils pourraient être sécurisés, leur combinaison pourrait ne pas l'être).
  • Si vous commencez à utiliser des directives tierces (composants) qui utilisent {{ }} dans leurs modèles, votre configuration les brisera. ( Correctif en attente )

Bien qu'il n'y ait rien que nous puissions faire au sujet du premier problème, sauf pour avertir les gens, nous devons aborder le deuxième problème.

Vous pouvez essayer une étiquette de modèle Django textuelle et l'utiliser comme ceci:

 {%load verbatim%} <p>{%verbatim%} <p>this where your angular tags "{{}}" resides <p>{%endverbatim%} 

Si vous avez séparé les sections de page correctement, vous pouvez facilement utiliser les balises angularjs dans la portée de la balise "brut".

Dans jinja2

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

Dans le modèle Django (ci-dessus 1.5)

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

Nous avons créé un filtre très simple dans Django 'ng' qui facilite le mixage des deux:

Foo.html:

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

Le filtre ng ressemble à ceci:

 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) 

J'ai donc grandement aidé dans la chaîne Angular IRC aujourd'hui. Il s'avère que vous pouvez changer facilement les étiquettes de modèle Angular. Les extraits nécessaires ci-dessous devraient être inclus après votre inclusion angulaire (l'exemple donné apparaît sur leurs listes de diffusion et utiliserait (()) comme les nouvelles étiquettes de modèle, se substituent à la vôtre):

 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); }); 

De plus, j'ai été signalé une amélioration à venir qui exposera les propriétés startSymbol et endSymbol qui peuvent être définies sur les balises que vous désirez.

Je vote contre l'utilisation de double parenthèses (()) comme étiquette de modèle. Cela peut bien fonctionner tant qu'aucun appel de fonction n'est impliqué, mais lorsque vous avez essayé ce qui suit

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

Avec Firefox (10.0.2) sur Mac J'ai eu une erreur terriblement longue au lieu de la logique prévue. <[]> S'est bien passé pour moi, au moins jusqu'à maintenant.

Edit 2012-03-29: Notez que $ invalidWidgets est obsolète. Cependant, j'utiliserais encore une autre enveloppe que les doubles accolades. Pour toute version angulaire supérieure à 0,10.7 (je suppose), vous pouvez modifier l'enveloppe beaucoup plus facilement dans la définition de votre application / module:

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

API docs .

J'ai trouvé le code ci-dessous utile. J'ai trouvé le code ici: http://djangosnippets.org/snippets/2787/

 """ filename: angularjs.py Usage: {% ng Some.angular.scope.content %} eg {% 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) 

Vous pouvez toujours utiliser ng-bind au lieu de {{}} http://docs.angularjs.org/api/ng/directive/ngBind

 <span ng-bind="name"></span> 

Si vous utilisez Django 1.5 et une utilisation plus récente:

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

Si vous êtes coincé avec django 1.2 sur appengine, étendez la syntaxe django avec la commande template textuelle comme celle-ci …

 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)) 

Dans votre fichier utilisez:

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

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

Pour AngularJS v1.3.3, vous devez définir vos propres tags de modèle comme celui-ci

Module AngularJS

 angular.module('myapp', []).config(function($interpolateProvider) { $interpolateProvider.startSymbol('{$'); $interpolateProvider.endSymbol('$}'); }); 

Page web

 <a>{$ variable $}</a> 

Vous pouvez indiquer à Django de sortir {{ et }} , ainsi que d'autres chaînes de modèles réservées en utilisant la balise {% templatetag %} .

Par exemple, l'utilisation de {% templatetag openvariable %} produirait {{ .

Je m'en tiendrais à une solution qui utilise à la fois les tags django {{}} et angularjs {{}} avec une section textuelle ou un modèle.

C'est simplement parce que vous pouvez modifier la façon dont angularjs fonctionne (comme mentionné) via $ interpolateProvider.startSymbol $ interpolateProvider.endSymbol mais si vous commencez à utiliser d'autres composants angularjs comme ui-bootstrap, vous constaterez que certains des modèles sont déjà construits Avec des balises angularjs standard {{}}.

Par exemple, consultez https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html .

Si vous faites une interpolation du côté du serveur, la seule manière correcte de le faire est de <>

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

Autre chose est un vecteur XSS.

C'est parce que les délimiteurs angulaires qui ne sont pas échappés par Django peuvent être entrés par l'utilisateur dans la chaîne interpolée; Si quelqu'un définit son nom d'utilisateur comme "{{evil_code}}", Angular l'exécutera avec plaisir . Si vous utilisez un caractère que Django échappe , cependant, cela n'arrivera pas.