javascriptjsrenderjsviews

Are there any use cases of using jsViews/jsRender with web components as the templating engine?


I'm writting some web components and I'd like to use jsViews $.link functionality as my templating engine. I've been able to use $.render to replace the .innerHTML of shadowRoot cloned content but I've only been able to use $.link in the following way. Just seems "dirty" to have to add an extra div to link to. Is there a better way to do this? Are there any performance issues here?:

const template = document.createElement('template');
template.innerHTML = `<div id="todo-item-tmpl"></div>`;

class TodoItem extends HTMLElement {
    constructor() {
        this._tmpl = $.templates('#todoItems');
        this._shadowRoot = this.attachShadow({ 'mode': 'open' });
        this._shadowRoot.appendChild(template.content.cloneNode(true));

        this._todoTmpl = this._shadowRoot.querySelector('#todo-item-tmpl');
        this._tmpl.link(this._todoTmpl, this._myDataObj);
    }
}

Solution

  • Here is possible approach, as shown in this modified version of your sample: https://jsfiddle.net/BorisMoore/z9wnyh5q/.

    Instead of defining the templates as content of script elements, they are defined using markup strings - to keep the HTML markup for the webcomponent itself.

    <html>
      <head>...</head>
      <body>
        <to-do-app></to-do-app>
      </body>
    </html>
    

    The item template can be a globally defined named template,

    $.templates("todoItemTmpl", todoItemTmpl}  // markup string for item template
    

    or can be scoped to the main template as a resource, (https://www.jsviews.com/#d.templates@tmpl-resources), for better encapsulation:

    this._tmpl = $.templates({
      markup: todoappTmpl, // markup string
      templates: {todoItemTmpl: todoItemTmpl}  // markup string for item template
    });
    

    The call to this._tmpl.link(this._wrapper, this._todos, this); (https://www.jsviews.com/#jsvtmpllink) needs to have as first parameter an HTML element (or jQuery selector) which is the container element wrapping the rendered data-linked content. It can't be directly a document fragment (the shadow root), so you need to provide the wrapper element (and optionally also insert a style element), e.g. by the following code:

    // Create a wrapper element
    this._wrapper = document.createElement('span');
    
    // and a style element...
    this._style = document.createElement('style');
    this._style.textContent = todoappStyle; // Stylesheet markup
    
    // Both inserted under the shadow root
    this._shadowRoot = this.attachShadow({ mode: "open" });
    this._shadowRoot.append(this._style, this._wrapper);
    
    // Render and data-link
    this._tmpl.link(this._wrapper, this._todos, this);