bigskysoftware / htmx

</> htmx - high power tools for HTML
https://htmx.org
Other
38.05k stars 1.29k forks source link

nunjucks client-side-templates #1322

Closed johntom closed 1 year ago

johntom commented 1 year ago

Hi, 1) If I load CSN.Html with live server the following example works as expected. 2) If I load page with fastify server using nunjucls the script tag does not get processed 3) Is there a way to process script tags when using nunjucks from a node server? TIA John

1 CSN.Html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>HTMX / Nunjucks</title>

  <script src='https://unpkg.com/htmx.org@1.8.5'></script>

  <script src="https://unpkg.com/nunjucks@3.2.3/browser/nunjucks.js"></script>

  <script src="/public/static/scriptall.js"></script>

</head>

<body>
  <h1> njk This only works from vs with a right mouse and Open with Live Server.
    <br> Test shows Client-side-templates runs scriptall but fails to run template
    <br> title {{ title }}
  </h1>
  <div hx-ext='client-side-templates'>
    <button hx-get="https://jsonplaceholder.typicode.com/users" 
    hx-target="#result"
     hx-swap="innerHTML"
      nunjucks-template="njtemplate">
      Handle with nunjucks
    </button>
  </div>
  <div id="result"></div>
  <script id="njtemplate" type="x-tmpl-nunjucks">
  {% for res in results %}
  {{res.name}}<br/>
  {% endfor %}
</script>
</body>
</html>

scriptall.js

htmx.defineExtension('client-side-templates', {
  transformResponse: function (text, xhr, elt) {
    var mustacheTemplate = htmx.closest(elt, "[mustache-template]");
    if (mustacheTemplate) {
      var data = JSON.parse(text);

      data = { results: data };// works
      console.log('mustache data', data)
      var templateId = mustacheTemplate.getAttribute('mustache-template');
      var template = htmx.find("#" + templateId);
      console.log(template);
      if (template) {
        return Mustache.render(template.innerHTML, data);
      } else {
        throw "Unknown mustache template: " + templateId;
      }
    }

    var handlebarsTemplate = htmx.closest(elt, "[handlebars-template]");
    if (handlebarsTemplate) {
      var data = JSON.parse(text);
      var templateName = handlebarsTemplate.getAttribute('handlebars-template');
      return Handlebars.partials[templateName]({ "data": data });
    }

    var nunjucksTemplate = htmx.closest(elt, "[nunjucks-template]");
    if (nunjucksTemplate) {
      var data = JSON.parse(text);
      data = { results: data };// works
      console.log('data', data)
      var templateName = nunjucksTemplate.getAttribute('nunjucks-template');
      console.log('templateName', templateName)
      var template = htmx.find('#' + templateName);
      console.log('template', template)
      if (template) {
        console.log('nunjucks', nunjucks)
        return nunjucks.renderString(template.innerHTML, data);
      } else {
        return nunjucks.render(templateName, { "data": data });
      }
    }
    return text;
  }
});

sc-0036

2

    fastify.get("/CSN",
    async (request, reply) => {
      reply.view('CSN.html', { title: 'MTMX CLIENT SIDE EXT NUNJUCKS' });
    });

1 change in scriptall.js when processing from node-fastify server

document.body.addEventListener('configRequest.htmx', function(evt) {
  // try to remove x-hx-* headers because gist api complains about CORS
  Object.keys(evt.detail.headers).forEach(function(key) { 
    delete evt.detail.headers[key]; 
  });
});

htmx.defineExtension('client-side-templates', {
  transformResponse: function (text, xhr, elt) {
    var mustacheTemplate = htmx.closest(elt, "[mustache-template]");
    if (mustacheTemplate) {
      var data = JSON.parse(text);

      data = { results: data };// works
      console.log('mustache data', data)
      var templateId = mustacheTemplate.getAttribute('mustache-template');
      var template = htmx.find("#" + templateId);
      console.log(template);
      if (template) {
        return Mustache.render(template.innerHTML, data);
      } else {
        throw "Unknown mustache template: " + templateId;
      }
    }

    var handlebarsTemplate = htmx.closest(elt, "[handlebars-template]");
    if (handlebarsTemplate) {
      var data = JSON.parse(text);
      var templateName = handlebarsTemplate.getAttribute('handlebars-template');
      return Handlebars.partials[templateName]({ "data": data });
    }
     var nunjucksTemplate = htmx.closest(elt, "[nunjucks-template]");
    if (nunjucksTemplate) {
      var data = JSON.parse(text);
      data = { results: data };// works
      console.log('data', data)
      var templateName = nunjucksTemplate.getAttribute('nunjucks-template');
      console.log('templateName', templateName)
      var template = htmx.find('#' + templateName);
      console.log('template', template)
      if (template) {
        console.log('nunjucks', nunjucks)
        return nunjucks.renderString(template.innerHTML, data);
      } else {
        return nunjucks.render(templateName, { "data": data });
      }
    }
    return text;
  }
});

the script is empty

Inkedsc-0037

and data does not loop

sc-0038

johntom commented 1 year ago

I just posted below yesterday on discord in htmx-general my workaround for this issue. codepen link https://codepen.io/johntom/pen/bGQNBXB Hi, no need to explain sending html from server as the best way for htmx as this was an exercise to figure out why client-side-extentions worked in codepen and failed on node server using fastify/nunjucks as backend. In my codepen https://codepen.io/johntom/pen/bGQNBXB button 1. Handle with nunjucks works as expected. button 2. Handle with nunjucks nodeserver only works works on nodeserver when I assign template in the js code provided in code pen. If I don't assign template.innerHTML nothing shows up. Commenting the assignment out of js code and you will see button1 work as expected. Any ideas on how to get the template to run without this modification?

johntom commented 1 year ago

passing the script in view also works. const search= {% for res in results %} title:{{res.title}}<br> body:{{res.body}}<br><hr>{% endfor %} return reply.view('CSNunjucks.njk', { title: 'CSNunjucks htmx features njk' , search:search});