Templates / Overview

Templates are just dom elements, that are used when a new component is being created manually not by parsing the DOM, but by calling Component.create static method / constructor.

Let's say users of our site can post comments. When the page loads, we might have some comments already on the page - for those, CommentComponent instances will be created automatically. However, when our user adds a new comment, we'll need to create a dom element to be appended to the comment's list. In this case, we first create an instance of the CommentComponent, which will search the DOM for the element with data-component-template="CommentComponent" attribute, clone it and assign the newly created component's dom element to the cloned element.

After that, we can add this newly created component to another component as a child, which will automatically append it to the parent's dom element.

Let's illustrate this with some code - and for simplicity, we'll make it so that new comments always have the same text - there will be no form to enter text and they are added simply by clicking the button. First, the html code:

Notice on line 3 we created a dom element for Component - why is that? That's because this will be our container for comments (as indicated by the assigned role). When creating new components from a template, we can specify a parent component and if we don't do that, components will be added as children to RootComponent, which isn't desirable in our case. But we still need a container and Component is perfect for it because we don't need any additional functionality.

This need for an actual component to be the container is probably a bit of an overcomplication. As of right now that's the only way to do things, but Webface.js will be adding the option to just specify an arbitrary dom element as a container, while implying the parent component.

Also notice that the element for the template is also automatically the first comment. While acceptable, it's not always desirable. If, for example, we were to delete all comments from the page, we would have no template, and trying to add a new comment would result in an error. Thus, perhaps it's better to make the template a separate element and to make it invisible:

And we are now ready to write the Javascript code that will actually create new comments when the button is clicked. We first will write the code for the CommentComponent class. It's going to be very short as we only need to specify the attribute in which comment text will be stored the attribute will be called text (who would've thought!).

export class CommentComponent extends extend_as("CommentComponent").mix(Component).with() {
  constructor() {
    super();
    this.attribute_names = ["text"];
  }
}

The button code will look a bit more complex as we need to do a bunch of things there:

export class AddCommentButtonComponent extends extend_as("AddCommentButtonComponent").mix(Component).with() {

  constructor() {
    super();
    this.native_events = ["click"];
    this.event_handlers.add({
      event: "click",
      role: "#self",
      handler: (self,event) => {
        CommentComponent.create({container: self.comment_container, attrs: { text: "New comment" }});
      }
    });
  
  afterInitialize() {
    this.comment_container = RootComponent.instance.findFirstChildByRole("comment_container");
  }

}

Don't get confused, line 15 will run before line 10! In line 14, we just decide what component instance is going to be the container for our comments. And the we just pass it to the CommentComponet.create() in an argument named container.

The static method Component.create (and its alias, Component.createFromTemplate()) is available in all components that inherit from Component and that's the method that does the heavy lifting of initializing everything, adding dom element and adding the newly created component to the right parent.

Component.create() accepts attrs argument and by passing an object with attribute names as keys you can that way set values for attributes in a newly created component.

When we run this code and click the button, our html is updated to look like this:

The power of templates is that they are non-obligatory. You may have a fully functional app written without any templates. It is only when you need to dynamically add new components onto the page you need templates. Even then, in some cases, you might decide to use an existing visible element as a template (as shown in the first version of the html for this usecase), since this simplifies the page itself.