DEV Community

Paul Kinlan
Paul Kinlan

Posted on • Originally published at paul.kinlan.me on

3

A simple clientside templating langauge

In a recent project, I wanted a simple way to bind some JSON data to a DOM element without importing any libraries and I think I came up with a pretty neat solution (in my eyes) that fit all my needs for the project.

The solution encodes templating instructions inside DOM data attributes nameddata-bind-*, which are accessible on the DOM element in the dataset property and it just so happens to camel-case the attributes automatically (i.e, to setinnerText you would have an attribute data-bind_inner-text - note the hyphen).

Here is a sample template from the project:

<template id="itemTemplate">
  <div class="item new" data-bind_id="guid" id="">
    <h3><span data-bind_inner-text="title"></span></h3>
    <p class="description" data-bind_inner-text="content:encoded|description"></p>
    <div>
      <a data-bind_href="link" data-bind_inner-text="pubDate" data-bind_title="title" href="" title=""></a>
      <svg class="share" url="" title="" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24">
        <path fill="none" d="M0 0h24v24H0z"></path><path d="M18 16c-.8 0-1.4.4-2 .8l-7-4v-1.5l7-4c.5.4 1.2.7 2 .7 1.7 0 3-1.3 3-3s-1.3-3-3-3-3 1.3-3 3v.7l-7 4C7.5 9.4 6.8 9 6 9c-1.7 0-3 1.3-3 3s1.3 3 3 3c.8 0 1.5-.3 2-.8l7.2 4.2v.6c0 1.6 1.2 3 2.8 3 1.6 0 3-1.4 3-3s-1.4-3-3-3z"></path>
      </svg>
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

As you can see, we use the <template> element to ensure that we can keep our HTML in the DOM and to keep it inert (this really improves the authoring experience). Note, it doesn’t have to be a template element, it can take anything that is inside the DOM.

To map the above DOM into an actual element with all the live data applied to it, I use the following basic algorithm:

  1. Clone the element to bind data on to.
  2. Iterate across the elements and for each element:
    1. Check to see if it has an attribute of the form data-bind_
    2. Get the keys to lookup on the data separated by a “|”
    3. Map the first found key’s value from the input data directly to the node’s attribute defined by data-bind_
  3. Return the new node.

The code for this is pretty simple, if a tad terse.

const applyTemplate = (templateElement, data) => {
  const element = templateElement.content.cloneNode(true);    
  const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT, () => NodeFilter.FILTER_ACCEPT);

  while(treeWalker.nextNode()) {
    const node = treeWalker.currentNode;
    for(let bindAttr in node.dataset) {
      let isBindableAttr = (bindAttr.indexOf('bind_') == 0) ? true : false;
      if(isBindableAttr) {
        let dataKeyString = node.dataset[bindAttr];
        let dataKeys = dataKeyString.split("|");
        let bindKey = bindAttr.substr(5);
        for(let dataKey of dataKeys) {
          if(dataKey in data && data[dataKey] !== "") {
            node[bindKey] = data[dataKey];
            break;
          }
        }
      }
    }
  }

  return element;
}
Enter fullscreen mode Exit fullscreen mode

I don’t expect anyone to use this, but I wanted to show how you can build a data binding tool for simple tasks without having to resort to a full library or framework.

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay