2012-03-24 12 views
19

Ich versuche, einen Adapter für ein Client-seitiges HTML/JS-Templating-System zu schreiben, um dust.js unter der Haube zu verwenden. Leider erwartet die API, dass Rendervorgänge synchron ablaufen: Die gerenderte Ausgabe sollte vom Aufruf render() zurückgegeben werden. Dust.js ist asynchron und übergibt die Renderausgabe an eine Rückruffunktion. Gibt es eine Möglichkeit, dies zu umgehen, entweder in den Dust-APIs oder durch einen verrückten Javascript-Hack?Ist es möglich, dust.js Templates synchron zu rendern?

+1

Gute Frage! Ich möchte das gleiche wissen, weil ich dust.js in einer CouchDB "show" -Funktion (serverseitig) verwenden möchte. –

+0

Hilft consolidate.js? – sntran

+0

Leider sieht es so aus, als ob die API, die von consolidate.js angeboten wird, eine Callback-Funktion auf die gleiche Weise wie dust.js verwendet, also glaube ich nicht, dass es hier helfen wird:/ –

Antwort

16

DustJS wird Objekte nur dann asynchron ausführen, wenn die Ressourcen, die es rendern muss (Vorlagen, Partials), noch nicht alle geladen wurden.

Wenn alle Abhängigkeiten einer Vorlage geladen sind, bevor Sie diese Vorlage ausführen, wird sie synchron ausgeführt (soweit ich das beurteilen kann). So können Sie so etwas wie tun:

var result; 
dust.render("tpl", data, function(err, res) { 
    result = res; 
}); 
console.log(result); // result will actually already be filled out if dustjs didn't 
// have to go look for resources somewhere. 

Hier ist ein vollständigeres Beispiel unten: (und hier ist ein jsfiddle Link, so können Sie ihn ausführen: http://jsfiddle.net/uzTrv/1/)

<script type="text/javascript" src="dust.js"></script> 
<script> 
    var tpl = dust.compile("Omg {#people} {.} {/people} are here! {>partial/}", "tpl"); 
    var partial = dust.compile("I'm a partial but I've already been included so things still run {how}", "partial"); 
    dust.loadSource(tpl); 
    dust.loadSource(partial); 

    var data = { 
     people: ["jim", "jane", "jack", "julie"], 
     how: "synchronously!" 
    }; 

    var result; 
    dust.render("tpl", data, function(err, res) { 
     result = res; 
    }); 
    console.log(result); 
</script> 

Es könnte Fälle geben (neben der, den ich erwähnt habe) wo ich falsch liege ... ich weiß nicht alles über dustjs.

+0

Geprüft. Das funktioniert, obwohl Sie sehr vorsichtig sein müssen, um nichts zu tun, was dazu führt, dass die Vorlage asynchron wird. – heneryville

+4

Eine Warnung: Das dust.onload (das zum verzögerten Laden von Vorlagen/Teiltabellen verwendet werden kann) ist nicht die einzige Sache, die asynchron sein kann. Alle benutzerdefinierten Helfer oder Funktionen in Ihren JSON-Daten können auch asynchron sein, indem Sie chunk.map aufrufen und dann einen Ajax-Aufruf, setTimeout usw. durchführen. Dies ist also definitiv keine vollständige Proof-Lösung. –

2

Ich wollte auch eine Funktion haben, die einen Kontext akzeptiert und den Staub gerendert Text zurückgegeben. Hier ist die Lösung, die ich kam mit:

// This function sets up dust template, and returns a new function "dusterFn()" 
// dusterFn() can be passed a Context, and will return the rendered text. 
// @param {String} text: The template text. 
// @param {String} [name]: The name of the template to register with dust. If none is provided, a random number is used. 
// @param {Function} [onError]: A function that is called if an error occurs during rendering. 
function getDusterFn(text, name, onError) { 

    var dusterFn = null; 
    name = name || Math.floor(Math.random() * 99999).toString(); 
    onError = onError || function (error) { }; 

    try { 

     var compiled = dust.compile(text, name) 
     dust.loadSource(compiled); 

     dusterFn = function (context) { 
      var dustOutput = ''; 
      dust.render(name, context, function (error, out) { 
       if (error) onError(error); 
       dustOutput = out; 
      }); 
      return dustOutput; 
     }; 

    } catch (e) { 
     // invalid template syntax 
     e += "\n\nPlease check your template syntax."; 
     throw (e); 
    } 

    return dusterFn; 

} 

Nutzungs

var greetingTemplate = getDusterFn('Hello {name}, You are {age} years old!'); 
greetingTemplate({name: 'Jane', age: 24}); 
0

Matts Lösung gab mir einige Hinweise, wie man ein kleines Wrapper zu schreiben, die die „Hässlichkeit“ seiner Lösung verbirgt sich (durch "Hässlichkeit" Ich meine Variable außerhalb des Callbacks deklarieren, Wert innerhalb Callback zuweisen und externen Callback zurückgeben).

Es bringt nicht nur den Hack in eine kleine Funktion, sondern bindet auch den Namen des Templates. Ich finde das unglaublich hilfreich, da ich dieselbe Renderfunktion immer und immer wieder benutze, aber ich möchte nicht jedes Mal den Namen der Vorlage angeben.

function templates(template) { 
    return function templatesWrapper(data) { 
    var result; 
    dust.render(template, data, function onRender(err, data) { 
     if (err) { 
     throw err; 
     } 
     result = data; 
    }); 
    return result; 
    } 
} 

Dies ist, wie es zu benutzen:

var renderHello = templates('hello.html'); 
renderHello({ username: 'Stackoverflow' }); 
// => <h1>Hello, Stackoverflow</h1> 
Verwandte Themen