Skip to content

Latest commit

 

History

History
132 lines (97 loc) · 5.28 KB

16.templates-repository.md

File metadata and controls

132 lines (97 loc) · 5.28 KB

Templates Repository

Introduction

We want to seperated html and js files so that we can seperate different code types and deal with proper minification during build time.
Additionally we want a way to easily get and manage templates.

For the most part, the bindable element will take care of this for you.
There are some frindge cases that you may run into so we will look at the api for this and then a frindge case and how to get past it.

A important point to note is that once a template has been registered, the binding engine will not remove it on your behalf.
The reason for this is that you may have frequently used components referenced in many screens and it makes more sense to leave the template in memory to speed up load operations. You are responsible to remove templates you no longer want in memory.

Api

This feature is found on crsbinding.templates.
The actual templates are stored on crsbinding.templates.data, but you should not really need to access it directly.
There are the functions available to help you manage the templates:

  1. load
  2. add
  3. get
  4. unload
  5. unloadAll

For the most part, "get" is your default function to use when interacting with the templates.
See the function details for more.

The data object for templates is just an object literal where the property name is the registered key (componentName) and the value is a HTMLTemplateElement

add

parameters: componentName, template

This is not a common usage function but allows you to register a HTMLTemplateElement with a given componentName. In reality you can use this for any time you want to store a template for cross UI usage. The component name is what ever key you want to get that object from the store object.

load

parameters: componentName, url

This function is for internal and external use. It loads the HTML from a file defined in the URL, creates a template for that HTML and stores the template for future use.
This function returns the newly created template. If you call load more than once for the same component name, it will not overwrite it, instead it will return the template already registered.

get

parameters: componentName, url

This is the main interaction function.
Here you define both the component name and the url.
If the template has not yet been set, it will load it via "load" and pass the HTML back for use. If a template already exists it will not read the file again instead it will return you the HTML of the existing template.

The url parameter is thus optional if you have already preloaded the template using the "load" function.

unload

parameters: componentNames

The parameter can be a single string or array of string of component names you want to remove from the store object.

unloadAll

no parameters

This function clears all store items so that no templates remain.

Fringe case

<template for="item of items">
    <child-component parent.bind="item"></child-component>
</template>

This HTML shows a repeated UI for each items object.
A new instance of "child-component" is created for each item.

The child component source looks like any simple component.

class ChildComponent extends BindableElement{
    get html() {
        return import.meta.url.replace(".js", ".html");
    }

    get parent() {
        return this.getProperty("parent");
    }

    set parent(newValue) {
        this.setProperty("parent", newValue);
    }
}

Under the hood it loads the HTML for the component and populates the innerHTML with the content of the HTML file.
The BindableElement class will interact with the templates and get the HTML from there.
The problem here is that if you have 20 child-components introduced in the parent's html, all of them load at the same time. Though it will work this is not idea because we want to limit file access.
Load the component HTML once and each time a new instance is created just get the html from memory.

This is where preloading templates come in.
Consider the master component's code

class MasterComponent extends BindableElement {
    get html() {
        return import.meta.url.replace(".js", ".html");
    }

    get items() {
        return this.getProperty("items");
    }

    set items(newValue) {
        this.setProperty("items", newValue);
    }

    async preLoad() {
        const path = crsbinding.utils.relativePathFrom(import.meta.url, "./child-component.html");
        await crsbinding.templates.load("ChildComponent", path);
    }
}

In the "preLoad" function we get the path to the HTML file we want to load.
We then add it to the templates using the "load" function.

Since the preLoad fires before the parsing of the master components HTML the child-component's template is ready by the time their connected callback fires.
None of the instances access the HTML file but instead loads them HTML content from the template store.

Preloading component's tempaltes in this way when you know they will be referenced soon is a good way to optimise their load time.
For the most part just using the standard bindable element is good enough as once a component was loaded for the first time all those who follow will laod from memory.

Where once you would have noticed the HTML in the network trafic per component instance, it now only loads it once and from then on, works from the template store.