Comment passer une variable du fichier Jade template vers un fichier script?

j'ai des problèmes avec une variable (config) déclarée dans un fichier Jade template (index.jade) qui n'est pas passé dans un fichier javascript, ce qui provoque alors la panne de mon javascript. Voici le fichier (vues/index.jade):

h1 #{title}

script(src='./socket.io/socket.io.js')
script(type='text/javascript')
  var config = {};
  config.address = '#{address}';
  config.port = '#{port}';
script(src='./javascripts/app.js')

Voici une partie de mon application.js (côté serveur):

  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.set('address', 'localhost');
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
    address: app.settings.address,
    port: app.settings.port
});
});

if (!module.parent) {
  app.listen(app.settings.port);
  console.log("Server listening on port %d",
app.settings.port);
}

// Start my Socket.io app and pass in the socket
require('./socketapp').start(io.listen(app));

Et voici une partie de mon fichier javascript qui se bloque (public/javascripts/app.js):

(function() {
        var socket = new io.Socket(config.address, {port: config.port, rememberTransport: false});

je dirige le site sur mode de développement (NODE_ENV=développement) sur localhost (ma propre machine). J'utilise node-inspector pour le débogage, qui m'a dit que la variable config n'est pas définie dans public/javascripts/app.js.

des idées?? Merci!!

102
demandé sur Michael Eilers Smith 2012-01-02 11:46:28

6 réponses

c'est un petit en retard mais...

script.
  loginName="#{login}";

ça marche très bien dans mon script. Dans l'Express, je fais ceci:

exports.index = function(req, res){
  res.render( 'index',  { layout:false, login: req.session.login } );
};

je suppose que le dernier jade est différent?

Merc.

edit: ajouté "."après script pour empêcher Jade warning.

146
répondu Merc 2014-01-28 21:07:08

!{} est pour sans échappement code interpolation, qui est plus approprié pour objets

script var data = !{JSON.stringify(data).replace(/<\//g, '<\/')}

{ foo: 'bar' }
// becomes:
<script>var data = {"foo":"bar"}</script>

{ foo: 'bar</script><script>alert("xss")//' }
// becomes:
<script>var data = {"foo":"bar<\/script><script>alert(\"xss\")//"}</script>

L'idée est d'empêcher l'attaquant de:

  1. sortir de la variable: JSON.stringify échappe à l'citations
  2. sortir de la balise script: si le contenu de variable (que vous avez peut-être pas capable de contrôler si vient de la base de données pour ex.) a une chaîne de caractères </script> , l'instruction replace s'en chargera

https://github.com/pugjs/pug/blob/355d3dae/examples/dynamicscript.pug


#{} est pour échappée interpolation de chaîne , qui est adapté uniquement si vous travaillez avec chaîne. ne fonctionne pas avec des objets

script var data = #{JSON.stringify(data)}

//=> <script>var data = {&quot;foo&quot;:&quot;bar&quot;}</script>
84
répondu laggingreflex 2016-06-26 22:05:29

dans mon cas, je tentais de passer un objet dans un gabarit via une route express (similaire à la configuration OPs). Puis j'ai voulu passer cet objet dans une fonction que j'appelais via une balise de script dans un modèle pug. Bien que la réponse de lagginreflex m'ait rapprochée, j'ai fini par la suivante:

script.
    var data = JSON.parse('!{JSON.stringify(routeObj)}');
    funcName(data)

cela assurait que l'objet était passé comme prévu, plutôt que d'avoir besoin de desérialiser dans la fonction. Aussi, les autres réponses semblaient fonctionne bien avec les primitives, mais lorsque les tableaux etc. ont été passés avec l'objet ils ont été analysés comme des valeurs de chaîne.

5
répondu Kyle Gillen 2018-05-12 02:57:03

voir cette question: JADE + EXPRESS: itération sur objet dans le code inline JS (côté client)?

j'ai le même problème. Jade ne passe pas de variables locales dans (ou ne fait pas de templating du tout) aux scripts javascript, il passe tout simplement le bloc entier en texte littéral. Si vous utilisez les variables locales 'adresse' et 'port' dans votre fichier Jade au-dessus de la balise script, elles devraient apparaître.

les solutions possibles sont énumérés dans la question que j'ai lié ci-dessus, mais vous pouvez: - passer chaque ligne dans un texte non enregistré (!= au début de chaque ligne), et il suffit de mettre "-" avant chaque ligne de javascript qui utilise une variable locale, ou: - Passer les variables par un élément dom et accéder par JQuery (ugly)

N'y a-t-il pas de meilleur moyen? Il semble que les créateurs de Jade ne veulent pas du support de javascript multiligne, comme le montre ce fil dans GitHub: https://github.com/visionmedia/jade/pull/405

2
répondu Varun Singh 2017-05-23 12:26:13

si vous êtes comme moi et que vous utilisez beaucoup cette méthode de passer des variables, voici une solution sans écriture de code.

dans votre noeud.js route, passer les variables dans un objet appelé window , comme ceci:

router.get('/', function (req, res, next) {
    res.render('index', {
        window: {
            instance: instance
        }
    });
});

puis dans votre fichier de mise en page pug/jade (juste avant le block content ), vous les sortez comme ceci:

if window
    each object, key in window
        script.
            window.!{key} = !{JSON.stringify(object)};

comme ma disposition.carlin fichier est chargé avec chaque carlin fichier, je n'ai pas besoin de "importer" mon variables et plus.

de cette façon toutes les variables/objets passés à window 'magiquement' finissent dans l'objet réel window de votre navigateur où vous pouvez les utiliser dans Reactjs, Angular, ... ou JavaScript vanille.

2
répondu Sam 2018-09-12 10:55:06

Voici comment j'ai résolu ce (utilisant un MOYEN de dérivés)

mes variables:

{
  NODE_ENV : development,
  ...
  ui_varables {
     var1: one,
     var2: two
  }
}

je devais D'abord m'assurer que les variables de configuration nécessaires étaient transmises. MEAN utilise le paquet node nconf, et par défaut est défini pour limiter quelles variables sont passées depuis l'environnement. J'ai dû y remédier:

config/config.js:

origine:

nconf.argv()
  .env(['PORT', 'NODE_ENV', 'FORCE_DB_SYNC'] ) // Load only these environment variables
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

après modifications:

nconf.argv()
  .env('__') // Load ALL environment variables
  // double-underscore replaces : as a way to denote hierarchy
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

maintenant je peux définir mes variables comme ceci:

export ui_varables__var1=first-value
export ui_varables__var2=second-value

Note: j'ai réinitialisé "heirarchy indicator" en "_ _ _ "(double underscore) parce que sa valeur par défaut était":", ce qui rend les variables plus difficiles à définir à partir de bash. Voir un autre post sur ce fil.

maintenant la partie jade: Ensuite, les valeurs doivent être rendues, afin que javascript puisse les récupérer du côté client. Un façon simple d'écrire ces valeurs dans le fichier index. Comme il s'agit d'une application d'une page (angulaire), cette page est toujours chargée en premier. Je pense qu'idéalement ce devrait être un fichier JavaScript include (juste pour garder les choses propres), mais c'est bon pour une démo.

app/controllers/index.js:

'use strict';
var config = require('../../config/config');

exports.render = function(req, res) {
  res.render('index', {
    user: req.user ? JSON.stringify(req.user) : "null",
    //new lines follow:
    config_defaults : {
       ui_defaults: JSON.stringify(config.configwriter_ui).replace(/<\//g, '<\/')  //NOTE: the replace is xss prevention
    }
  });
};

app/views/index.jade:

extends layouts/default

block content
  section(ui-view)
    script(type="text/javascript").
    window.user = !{user};
    //new line here
    defaults = !{config_defaults.ui_defaults};

dans mon html rendu, cela donne un gentil petit script:

<script type="text/javascript">
 window.user = null;         
 defaults = {"var1":"first-value","var2:"second-value"};
</script>        

A partir de là, il est facile pour angular d'utiliser le code.

1
répondu Michael 2016-10-19 02:04:49