2.9.16
Coherent GT
A modern user interface library for games
Components

Table of Contents

Coherent GT allows for easy communication between your application and the UI via several mechanisms.

Components

Components consists of several separate technologies. You can think of Components as reusable user interface widgets.

  • data-bind-model: Works like engine.attachToModel on the DOM element on which the attribute is applied. You can access the attached model properties with the keyword "this".
  • data-bind-template: Inserts HTML template inside the DOM element on which the attribute is applied.
  • data-bind-template-name: This attribute is placed on a script tag with value the name of the template. It registeres a component with this name. The HTML template is registered with data-bind-template-name or engine.registerComponent. data-bind-template and data-bind-model work correctly together.
  • <link rel="import" href="folder/Name.html">: This link import functionality parses the HTML file by a given URL and inserts all:
    • Other link imports from the file.
    • Link style elements.
    • Script tags.
    • Style tags. to the main html file. For now you can't use relative routes to resources in inline css because they won't work. If you need to do this use absolute URLs or write all your CSS in separated file.
  1. If you want the template to be registered as Component directly from the html you must add data-bind-template-name="ComponentName" as attribute to the script tag. Registered components from the HTML, don't have callbacks for now.
    <script type="text/html" id="item-template" data-bind-template-name="ComponentName">
    <div class="list-item">
    <div class="item-name" data-bind-value="{{this.name}}" >Item Name</div>
    </div>
    </script>
  2. If you want to register the component from the JavaScript, the script tag must not contain data-bind-template-name. After the template has been defined, instantiate it and register the component:

    <script>
    function instantiateTemplate(selector) {
    var template = document.querySelector(selector),
    div = document.createElement('div');
    div.innerHTML = template.textContent;
    return div;
    }
    var instance = instantiateTemplate('#item-template');
    engine.registerComponent("listItem", {
    template: instance,
    create: function () { },
    });
    </script>

    The registerComponent method has 3 arguments:

    • The first one is the name of the component(template). With this name we call data-bind-template="name" attribute.
    • The second one is a DOM element which would be inserted as template.
    • The third is a callback functions which is called on insertion of the template.


  3. After registering the component, you can use it with data-bind-template attribute and the name you have given to the component, for example:
    <div id="list-container">
    <div data-bind-for="i:{{game.weapons}}">
    <div data-bind-template="listItem" data-bind-model="{{i}}"></div>
    </div>
    </div>
  4. Public JS methods
    • JavaScript Component Object - Each registered component from engine.registerComponent() or <script data-bind-model-name=”componentName”></script> would have JavaScript object representation. This JavaScript Object would contain addEvents method.
    • engine.getComponentInstance(domElement) - Traverses upwards the DOM tree by a given DOM Node and searches for data-bind-template and data-internal-bind-template-set attributes. Returns an object containing the JavaScript object of the component used on this DOM element and the DOM Instance on which the component is used.
    • engine.getBoundModelForComponent(domElement) - Traverses upwards the DOM tree by a given DOM Node and searches for data-bind-model attribute and returns JavaScript object of the model attached.
    • engine.getComponent(name) - Return a component JavaScript Object by a given name. Returns null if there is no component with the given name.
    • component.addEvents(json) - Inserts callbacks inside the component object that can be used in data-bind event attributes. When given callbacks with name "create" or "remove" adds special events that are called on component creation and deletion.
    • New {{component}} keyword for data-bind attribute values. Currently it can be used only in data-bind event attributes. This would give you the object that represents a component, similar as {{this}} which represents the currently attached model. With {{component}} you can access all component callbacks you’ve added to them.
<script type="text/html" data-bind-template-name="ComponentName">
<div class="wrapper">
<button data-bind-click="{{component}}.callback(event, {{this}}, this)"></button>
</div>
</script>
<div id="component-div" data-bind-model={{g_Player}} data-bind-template="ComponentName"></div>
// component would be the JavaScript representation of the registered component with name - "ComponentName".
let component = engine.getComponent('ComponentName');
// By adding events to the component object we can then access them via "{{component}}.callback" syntax
// inside data-bind event attributes.
component.addEvents({
callback: (event, thisObject, domElement) => {
// thisObject is equal to g_Player, the model given to data-bind-model.
let componentInstance = engine.getComponentInstance(domElement);
let componentModel = engine.getBoundModelForComponent(domElement); // componentModel would be equal to thisObject.
// componentInstance.component == component (The component JavaScript representation).
// componentInstance.componentInstance - The DomElement on which the component is used.
// the id of componentInstance.componentInstance is "component-div".
});

Known issues

  1. Mixing data-bind-for with data-bind-model on the same element. If data-bind-for collection's model and collection's elements have the same property name and it is used in the data binding, then the result would be undefined. For example:
<head>
<script>
engine.on('Ready', function() {
engine.createJSModel('model', {
values: [{x:1}, {x:2}, {x:3}],
x: 42
});
});
</script>
</head>
<body>
<script type="text/html" data-bind-template-name="js-inner">
<div data-bind-value="{{this.x}}"></div>
</script>
<div data-bind-for="iter:{{model.values}}" data-bind-model="{{iter}}" data-bind-template="js-inner">
</body>

There are two approaches to to get the same functionality.

  • To remove collisions of the names
    <head>
    <script>
    engine.on('Ready', function() {
    engine.createJSModel('model', {
    values: [{x:1}, {x:2}, {x:3}],
    y: 42
    });
    });
    </script>
    </head>
    <body>
    <script type="text/html" data-bind-template-name="js-inner">
    <div data-bind-value="{{this.x}}"></div>
    </script>
    <div data-bind-for="iter:{{model.values}}" data-bind-model="{{iter}}" data-bind-template="js-inner">
    </body>
  • To separate data-bind-for and data-bind-model on different elements.
    <head>
    <script>
    engine.on('Ready', function() {
    engine.createJSModel('model', {
    values: [{x:1}, {x:2}, {x:3}],
    x: 42
    });
    });
    </script>
    </head>
    <body>
    <script type="text/html" data-bind-template-name="js-inner">
    <div data-bind-value="{{this.x}}"></div>
    </script>
    <div data-bind-for="iter:{{model.values}}">
    <div data-bind-model="{{iter}}" data-bind-template="js-inner"></div>
    </div>
    </body>