frumbert
frumbert

Reputation: 2427

using fetch to then compile a handlebarsjs template inside a promise

Fetching data using fetch then executing it with Handlebars is easy enough when you've already compiled your templates ..

var template        = Handlebars.compile(the-html);
fetch('data.json')
   .then(function(response) {
      return response.json();
   })
   .then(function(json) {
      var html = template(json[0]);
      // use this somehow
   });

But I want to fetch a number of files (markup and script that contain handlebars tags) based on some path that was pre-determined in the promise chain, and compile them as Handlebars templates and then apply these to some model I previously prepared, inside a promise chain.

var json = {some-data};
some-promise-step()
.then(function(json) {
   var templates = Handlebars.templates = Handlebars.templates || {}; // global handlebars object
   var urls = ["/abc/templates/" + json.template + "/index.html", "/abc/templates/" + json.template + "/style.css", "/abc/templates/" + json.template + "/script.js"]; // simplified
   var promises = urls.map(function(url) {
      return fetch(url).then(function(response) {
         var name = response.url.split("/").pop();
         return response.text().then(function(data) {
            templates[name] = Handlebars.compile(data);
         });
      });
   });
   return Promise.all(promises);
}).then(function(result) { // result is an array of 'undefined' ?? hmm
  return Promise.all([
    zip.file("index.html", Handlebars.templates["index.html"](json)),
    zip.file("style.css", Handlebars.templates["style.css"](json)),
    zip.file("script.js", Handlebars.templates["script.js"](json)),
  ]);
}).then( // more steps 

Handlebars needs to compile into the global Handlebars.templates[] object (which already exists) before they can be used by the next step (in which the zip object is fed the output of the applied template and returns a promise)

But by the time the fetches have returned and the .text() method returns to compile the template, the outer promise has resolved and started trying to use the templates.

I don't want the final .then( to begin doing what it needs to until after the fetch promises have all resolved...

Upvotes: 1

Views: 1339

Answers (1)

frumbert
frumbert

Reputation: 2427

Aha! Don't return the fetch promise; return a promise that resolves when the fetch's response.text() promise concludes.

var promises = urls.map(function(url) {
    return new Promise(function(resolve,reject) {
        fetch(url).then(function(response) {
            var name = response.url.split("/").pop();
            return response.text().then(function(html) {
                templates[name] = Handlebars.compile(html);
                resolve(name);
            });
        });
    });
});
return Promise.all(promises);

Could still optimise this whole idea further, but this seems to work for now.

Upvotes: 1

Related Questions