Templates

Most Components of this library come with a Template, and this Template can be replaced without changing the Component code. This is useful if you want add/remove or rearange the DOM nodes that are used to render a widget.

We will illustrate this by customizing the way a Conversation Item is rendered in the Conversation List. Our task: remove last_message and the delete button, and put a menu button in its place.

The original template layer-conversation-item.html:

<template>
  <style>
  /* original CSS rules hidden to keep this concise */
  </style>
  <div class='layer-list-item' layer-id='innerNode'>
    <layer-avatar layer-id='avatar'></layer-avatar>
    <div class='layer-conversation-item-content'>
      <layer-conversation-title layer-id='title'></layer-conversation-title>
      <layer-conversation-last-message layer-id='lastMessage'></layer-conversation-last-message>
    </div>
    <layer-delete layer-id='delete'></layer-delete>
  </div>
</template>
<script>
  window.layerUI.registerTemplate('layer-conversation-item');
</script>

Lets create a new file, called my-conversation-item.html:

<template>
  <style>
  /* your CSS rules */
  </style>
  <div class='layer-list-item' layer-id='innerNode'>
    <layer-avatar layer-id='avatar'></layer-avatar>
    <div class='layer-conversation-item-content'>
      <div class='layer-conversation-item-title' layer-id='title'></div>
      <!-- <layer-conversation-last-message layer-id='lastMessage'></layer-conversation-last-message>  -->
    </div>
    <!-- <layer-delete layer-id='delete'></layer-delete> -->
    <!-- Adding this line -->
    <span class='custom-conversation-item-menu' layer-id='menu'>Menu</span>
  </div>
</template>
<script>
  window.layerUI.registerTemplate('layer-conversation-item');
</script>

Note

If you are using a template file with multiple templates, change the registerTemplate call to:

<template id='template1'></template>
<template id='template2'></template>
<template id='template3'></template>
<script>
  var template1 = document._currentScript.ownerDocument.getElementById('template1');
  window.layerUI.registerTemplate('layer-conversation-item', template1);
</script>

Template IDs

A template may be given an ID; the example with a single template does not require an ID; the example with multiple templates requires IDs.

In either case, we all window.layerUI.registerTemplate; if the document that makes that call has a single template, then registerTemplate will find that automatically and associate it with the specified widget. If there are multiple templates in your file, then the function can not automatically identify the relevant template, and you must pass the template in as a parameter.

Putting multiple templates in a single file reduces the number of requests to your server. See Defining Build Friendly Templates for other ways to optimize your build.

The layer-id Attribute

The layer-id attribute assigns a name to the DOM node that allows the widget to to directly access it. By having layer-id="title", we have told the widget to setup the property widget.nodes.title to refer to the layer-conversation-item-title node. By adding layer-id='menu' we have made it so we can use widget.nodes.menu to access our new button.

<template>
  <div layer-id='innerNode'>
    <layer-avatar layer-id='avatar'></layer-avatar>
    <div layer-id='title'></div>
  </div>
  <layer-delete layer-id='delete'></layer-delete>
</template>

The above template will allow our class to access the following properties as early as the onCreate method of the Component Lifecycle:

layerUI.registerComponent('my-sample-widget', {
  methods: {
    onCreate() {
      this.nodes.innerNode.addEventListener('onmouseover', this.onMouseOver.bind(this));
      this.nodes.avatar.users = [client.user];
      this.nodes.delete.item = someMessage;
    }
  }
});

Safely Customizing Templates

Building a template for an existing Component requires you to know what layer-id names the widget expects to have available. Most widgets will test for the existence of the named item before using them, but you must insure that required ones have been defined in your html file. Its recommended that if you replace the component for an existing widget, that you start with a copy of the original template, adjust a few nodes at a time, and retest to make sure that no errors are thrown due to missing layer-id named nodes.

Template Styling

Each template within the file has its own optional <style/> section. When designing your CSS rules, we recommend the following:

Layer UI does not use Shadow DOM, therefore, you should prefix all of your CSS rules with the component name. If you are targeting .title in your rule, it should be my-sample-widget .title in your rule.

<template>
  <style>
  my-sample-widget {
    display: block;
  }
  my-sample-widget > div {
    width: 200px;
  }
  my-sample-widget layer-avatar {
    margin-right: 20px;
  }
  </style>
  <div layer-id='innerNode'>
    <layer-avatar layer-id='avatar'></layer-avatar>
    <div layer-id='title'></div>
  </div>
  <layer-delete layer-id='delete'></layer-delete>
</template>

Note

A Webcomponent has a default display styling that is unset. A typical component should at a minimum define a display style to insure it renders in a predictable fashion. The example above sets display: block.

It is tempting to put all css for styling your component into the template. However, recommended practice is to put the minimum required CSS into the template needed to insure a proper layout, and to leave the rest of its styling to your themes and application style sheets. You want your title to be blue and bold? There are probably other places in your application theme where text is blue and bold; and your application theme is a cleaner place to change that then tweaking your template for every style change.

Custom Templates for List Items

All List Items (<layer-message-item />, <layer-conversation-item />, <layer-identity-item />, etc…) have an item property representing the item of data within the list that they are rendering. They will pass this item to any node in their template that contains a layer-id. Example:

<template>
  <div class='layer-list-item' layer-id='innerNode'>`
    <my-custom-widget-1 layer-id='widget1'></my-custom-widget-1>
    <my-custom-widget-2 layer-id='widget2'></my-custom-widget-2>
    <my-custom-widget-3 layer-id='widget3'></my-custom-widget-3>
    <my-custom-widget-4></my-custom-widget-4>
  </div>
</template>

If you have defined Custom Components my-custom-widget-1 through my-custom-widget-4, and defined an item property for them, they should expect to have their item property set automatically… except for my-custom-widget-4 above which did not define a layer-id.

This means you do in fact have the means of modifying a template without having to customize the component’s code to pass data around.

Its also important to note that All List Items expect their templates to have everything contained within the following node: <div class='layer-list-item' layer-id='innerNode'>; this should be maintained in any template you make for any type of List Item.

Defining Build Friendly Templates

You may call:

layerUI.buildAndRegisterTemplate('my-component-name', myHTMLTemplateString);

This will convert that HTML string into a template for your component. This is useful as it means you can store your template as a string within a single build file instead of having to load it separately at runtime using:

<link rel="import" href="component.html" >

Note

buildAndRegisterTemplate will fail if the string contains <style/> tags or <script/> tags. this function is designed for DOM Structure only.

Instead of putting all your styles and HTML into your template, you can separately register your styles as part of the component using layerUI.buildStyle. This could be done as part of a build step:

// Sets templateContent to a string with the contents of your template file
var templateContents = grunt.file.read('template.html');

// returns css rules, without any `<style>` html tags.
var styles = extractStyles(templateContents);

// Returns all HTML, minus the `<style>` and `<template>` tags
var nodes = extractNodes(templateContents);

// Register the HTML as the template for my-widget
layerUI.buildAndRegisterTemplate('my-widget', nodes);

// Register the CSS as styling for my-widget
layerUI.buildStyle('my-widget', styles);

Given a template of:

<template>
  <style>
  my-sample-widget {
    display: block;
  }
  my-sample-widget > div {
    width: 200px;
  }
  my-sample-widget layer-avatar {
    margin-right: 20px;
  }
  </style>
  <div layer-id='innerNode'>
    <layer-avatar layer-id='avatar'></layer-avatar>
    <div layer-id='title'></div>
  </div>
  <layer-delete layer-id='delete'></layer-delete>
</template>

The styles variable should equal:

my-sample-widget {
  display: block;
}
my-sample-widget > div {
  width: 200px;
}
my-sample-widget layer-avatar {
  margin-right: 20px;
}

and the nodes variable should equal:

<div layer-id='innerNode'>
  <layer-avatar layer-id='avatar'></layer-avatar>
  <div layer-id='title'></div>
</div>
<layer-delete layer-id='delete'></layer-delete>
Best Practices Theming