Come passare la variabile dal file modello jade a un file script?


119

Ho problemi con una variabile (config) dichiarata in un file modello jade (index.jade) che non viene passata a un file javascript, il che provoca il blocco del mio javascript. Ecco il file (views / 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')

Ecco una parte del mio app.js (lato server):

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

Ed ecco una parte del mio file javascript che si arresta in modo anomalo (public / javascripts / app.js):

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

Sto eseguendo il sito in modalità di sviluppo (NODE_ENV = sviluppo) su localhost (la mia macchina). Sto usando node-inspector per il debug, che mi ha detto che la variabile di configurazione non è definita in public / javascripts / app.js.

Qualche idea?? Grazie!!


Risposte:


174

È un po ' tardi ma ...

script.
  loginName="#{login}";

Funziona bene nel mio script. In Express, sto facendo questo:

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

Immagino che l'ultima giada sia diversa?

Merc.

modifica: aggiunto "." dopo lo script per impedire l'avviso di Jade.


1
Grazie per aver accettato la risposta! Allora, qual era il vero problema con il tuo codice?
Merc

Sì, ho ottenuto questo funzionamento anche racchiudendo la variabile locale nel modello tra virgolette e l'indicatore # {}.
Askdesigners

Questa risposta è pericolosa, la risposta di lagginreflex codifica correttamente la stringa (le nuove righe nel nome di accesso potrebbero consentire l'esecuzione del codice).
Paul Grove

Quindi il problema erano solo le virgolette singole mentre sono previste doppie, giusto?
Augustin Riedinger

Per me il problema era il punto. Lo avevo alla fine del blocco di script. Con il punto dopo la parola chiave "script" funziona a meraviglia. Grazie!
Mirko

103

!{}è per l' interpolazione del codice senza caratteri di escape, che è più adatta per gli oggetti

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'idea è impedire all'aggressore di:

  1. Rompi la variabile: JSON.stringifyevita le virgolette
  2. Rompi il tag script: se il contenuto della variabile (che potresti non essere in grado di controllare se proviene dal database, ad esempio) ha una </script>stringa, l'istruzione replace si prenderà cura di essa

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


#{}è per l' interpolazione di stringhe con escape , che è adatta solo se si lavora con stringhe. Non funziona con gli oggetti

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

//=> <script>var data = {&quot;foo&quot;:&quot;bar&quot;}</script>

1
Ottima risposta! Ho cercato questo argomento per più di 20 minuti e nessun'altra risposta ha indicato la differenza tra! {} E # {}. Per tutto questo tempo ho pensato che! {] Fosse l'equivalente deprecato di # {} ... Grazie ancora.
Patrick E.

In alto! Bella risposta.
Scarysize

Ottima risposta e funziona per gli oggetti! A proposito, è JSONun oggetto globale? Sembrava funzionare senza importare altre librerie. In caso affermativo, per quanto riguarda il supporto del browser?
chharvey

@chharvey JSON è un linguaggio javascript integrato (come Date o Math), tutti i browser lo supportano.
laggingreflex

1
D'accordo, questa è la risposta migliore, ma non credo che questo sia il posto giusto per sfuggire a stringhe potenzialmente pericolose. IMO sarebbe meglio omettere la replacechiamata in questo codice e trattare questo valore come qualsiasi altro input. È garantito che JSON.stringify produca javascript valido (o fallisca) e, dopo aver memorizzato questo valore potenzialmente pericoloso, puoi assicurarti di disinfettarlo secondo necessità prima dell'uso.
Riley Lark

9

Nel mio caso, stavo tentando di passare un oggetto in un modello tramite un percorso espresso (simile alla configurazione degli OP). Quindi ho voluto passare quell'oggetto in una funzione che stavo chiamando tramite un tag di script in un modello pug. Sebbene la risposta di lagginreflex mi abbia avvicinato, ho concluso con quanto segue:

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

Ciò ha garantito che l'oggetto fosse passato come previsto, invece di dover deserializzare nella funzione. Inoltre, le altre risposte sembravano funzionare bene con le primitive, ma quando gli array ecc. Venivano passati insieme all'oggetto venivano analizzati come valori stringa.


7

Se sei come me e usi molto questo metodo per passare le variabili, ecco una soluzione di codice senza scrittura.

Nella tua rotta node.js, passa le variabili in un oggetto chiamato window, in questo modo:

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

Quindi nel tuo file di layout pug / jade (appena prima del block content), li ottieni in questo modo:

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

Poiché il mio file layout.pug viene caricato con ogni file pug, non ho bisogno di "importare" le mie variabili più e più volte.

In questo modo tutte le variabili / oggetti passati a window'magicamente' finiscono windownell'oggetto reale del tuo browser dove puoi usarli in Reactjs, Angular, ... o vanilla javascript.


1
Questa è la migliore risposta che ho visto.
Tohir

3

Ecco come ho affrontato questo problema (usando un derivato MEDIO)

Le mie variabili:

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

Per prima cosa dovevo assicurarmi che fossero passate le variabili di configurazione necessarie. MEAN utilizza il pacchetto node nconf e per impostazione predefinita è impostato per limitare le variabili che vengono passate dall'ambiente. Ho dovuto rimediare a questo:

config / config.js:

originale:

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

dopo le modifiche:

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

Ora posso impostare le mie variabili in questo modo:

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

Nota: ho reimpostato l '"indicatore di gerarchia" su "__" (doppio trattino basso) perché il suo valore predefinito era ":", il che rende le variabili più difficili da impostare da bash. Vedi un altro post su questo thread.

Ora la parte jade: Successivamente i valori devono essere renderizzati, in modo che javascript possa prenderli dal lato client. Un modo semplice per scrivere questi valori nel file di indice. Poiché si tratta di un'app di una pagina (angolare), questa pagina viene sempre caricata per prima. Penso che idealmente questo dovrebbe essere un file di inclusione javascript (solo per mantenere le cose pulite), ma questo è buono per una demo.

app / controller / 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};

Nel mio HTML renderizzato, questo mi dà un bel piccolo script:

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

Da questo punto è facile per angular utilizzare il codice.


Questo è un modo molto prolisso per dire ciò che dice già la risposta accettata. Inoltre, menzionare MEAN, nconf ecc. Sono irrilevanti. La domanda riguarda come passare le variabili al client, non come hai fatto il tuo stack di sviluppo. Non downvoting però, dal momento che ti impegni ancora molto in questa risposta.
Mrchief

eccessivamente complicato
andygoestohollywood

2

Vedi questa domanda: JADE + EXPRESS: Iterazione sull'oggetto nel codice JS inline (lato client)?

Ho lo stesso problema. Jade non passa le variabili locali (o non esegue alcun modello) agli script javascript, semplicemente passa l'intero blocco come testo letterale. Se utilizzi le variabili locali "indirizzo" e "porta" nel tuo file Jade sopra il tag dello script, dovrebbero essere visualizzate.

Le possibili soluzioni sono elencate nella domanda che ho collegato sopra, ma puoi: - passare ogni riga come testo senza caratteri di escape (! = All'inizio di ogni riga), e semplicemente mettere "-" prima di ogni riga di javascript che utilizza un variabile locale, oppure: - Passa le variabili attraverso un elemento dom e accedi tramite JQuery (brutto)

Non c'è modo migliore? Sembra che i creatori di Jade non vogliano il supporto javascript multilinea, come mostrato da questo thread in GitHub: https://github.com/visionmedia/jade/pull/405

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.