Skip to content

Latest commit

 

History

History
118 lines (92 loc) · 4.02 KB

17. UI hotswap.md

File metadata and controls

118 lines (92 loc) · 4.02 KB

UI Hotswapping

Introduction

This is the ability to swap UI parts in and out based on requirement.
This goes beyond just showing and hiding UI it adds and removes elements in the DOM.
This should be used mindfully because any time you add or remove items from the DOM can be expensive.

In scenarios when you do this on a user action it is acceptable.
Trying to perform this kind of operation on a frequent loop N amount of times per second is not.

Scenarios

There are three main scenarios we will cover here.

  1. As part of a self contained component.
  2. Using perspective-element as part of a parent context.
  3. Using perspective-element to load HTML fragments.

Basics

Either way the content is defined as template elements.
Each template must have a data-id attribute that defines the view id.
One of the templates must be marked as default using the data-default="true" attribute.

Component Example

javascript

export class ToolbarElement extends crsbinding.classes.PerspectiveElement {
    get html() {
        return import.meta.url.replace(".js", ".html");
    }
}

customElements.define("toolbar-element", ToolbarElement);

html

<template data-id="view1" data-default="true">
    <button data-id="add">Add</button>
    <button data-id="delete">Delete</button>
</template>

<template data-id="view2">
    <button data-id="show">Show</button>
    <button data-id="post">Post</button>
</template>

This example works much the same way as a Bindable Element where the content of the element is found in a separate HTML file. The element marked as default will be loaded automatically. If you want to change the content you need to set the view property to the id of the template you want to show.

perspective-element with shared context example

This example works well for example:

  1. Wizards
  2. Schema generated UI
<perspective-element data-store="perspective1" view.bind="selected" ctx.once="context">
    <template data-id="person" data-default="true">
        <label>
            <div>First Name</div>
            <input value.bind="model.person.firstName" />
        </label>
        ...
    </template>

    <template data-id="address">
        <label>
            <div>Street 1</div>
            <input value.bind="model.address.street1" />
        </label>
        ...
    </template>
</perspective-element>

Couple of things to take note of:
The store id is based on either one of two things:

  1. The element constructor name
  2. data-store value

When you want to use more than one perspective-element on the same view but, it contains different content, you will need to define a unique store using data-store. In this example we are also changing the view through a binding expression.
Since this example does not have it's own context but should use the context of the containing view we pass the context on using the context.once attribute.

Note that your view base needs to set the context.

this.setProperty("context", this._dataId);

perspective-element with fragments

This example loads content dynamically using fragments.

This example is useful for conditional content.
Only load the content if and when it's required.
The previous example assumes you will need all that UI at some stage during the usage.
This example makes no such assumption.

<perspective-element data-store="perspective2" view.bind="selected" ctx.once="context" data-folder="/app/perspective-element/">
    <template data-id="person" data-default="true">
        <template src="./templates/person.html"></template>
    </template>
    <template data-id="address">
        <template src="./templates/address.html"></template>
    </template>
</perspective-element>

Because this example uses fragments, you need to define the folder from where the templates must be loaded.
This is done by setting the data-folder attribute.
The template src must be relative to this data folder.