jComponent / 08. Data Binding
Updated: 29. November 2018
Author: Peter Širka

08. Data Binding

Professional Support Chat with contributors

Data-Binding is a special feature in jComponent. It can affect DOM element dynamically.

Topics:


Declaration:

<div data-bind="path.to.property__command1:exp__command2:exp__commandN:exp"></div>

Commands

command: change

Expression must be a link to the function. This function will be executed if the data-bind path will be changed.

<div data-bind="some.path__change:myfunction"></div>

<script>
    function myfunction(value, path, element) {
        console.log('VALUE HAS BEEN CHANGED:', value);
    }
</script>

command: checked

Sets the checked attribute. Targeted for HTML controls only input. Expression must return Boolean.

<input data-bind="some.path__checked:value" />

command: class

Toggles specified class when the data-bind is processed. Epression must be String only. Supports multiple classes seperated by empty space.

<div data-bind="some.path__class:hidden" class="hidden">READY</div>

<!-- Or multiple classes: -->
<div data-bind="some.path__class:hidden ready" class="hidden">READY</div>

command: config

Performs reconfiguration for the current jComponent. Expression must return String with jComponent configuration or can return Object.

<div data-bind="some.path__config:'required:' + (value === true)" data-jc="textbox">My textbox</div>

<!-- Sets "required" for all nested jComponents -->
<div data-bind="some.path__config [data-jc]:'required:' + (value === true)">
    <div data-jc="textbox"></div>
    <div data-jc="dropdown"></div>
    etc..
</div>

command: def

Sets the disabled attribute. It's targeted for HTML controls only input, textarea, select and button.

String:
<div data-bind="some.path__def:'String'__html:JSON.strignify(value)"></div>

Number:
<div data-bind="some.path__def:100__html:JSON.strignify(value)"></div>

Boolean:
<div data-bind="some.path__def:true__html:JSON.strignify(value)"></div>

Object:
<div data-bind="some.path__def:{}__html:JSON.strignify(value)"></div>

Array:
<div data-bind="some.path__def:[]__html:JSON.strignify(value)"></div>

command: delay

Delays a binding for 2 seconds. Must be a number which represents milliseconds.

<input data-bind="some.path__val:value__delay:2000" />

command: disabled

Sets the disabled attribute. It's targeted for HTML controls only input, textarea, select and button. Expression must return Boolean.

<input data-bind="some.path__disabled:value" />

command: enabled

+v16 Sets the disabled attribute. It's targeted for HTML controls only input, textarea, select and button. Expression must return Boolean.

<input data-bind="some.path__enabled:value" />

command: hide

Toggles hidden class. Expression must return Boolean.

<div data-bind="some.path__hide:value"></div>
<div data-bind="some.path__hide:value !== 'users'"></div>

command: href

Sets href attribute. It's targeted for links <a> only. Expression must return String.

<div data-bind="some.path__href:value"></div>

command: html

Sets the value as the HTML content. Expression must return String.

<div data-bind="some.path__html:value"></div>
<div data-bind="some.path__html:value.toUpperCase()"></div>

command: import

Performs IMPORT(). Expression must be URL address String or (+v16) value must return a valid URL adress.

This command imports each resource only one time.

<div data-bind="some.path__import:https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></div>

<div data-bind="some.path__import:value"></div>

command: invisible

+v16 sets invisible class to this element if the condition is valid. invisible class is a part of spa.min.css and it's declaration is .invisible { visibility: hidden; }. Usage:

<div data-bind="some.path__invisible:value == true"></div>

command: setter

+v16 performs element.SETTER() for nested components.

<div data-bind="some.path__setter:'datagrid','resize'"></div>
<!-- performs: element.SETTER('datagrid', 'resize') -->

<div data-bind="some.path__setter:true,'datagrid','resize'"></div>
<!-- performs: element.SETTER(true, 'datagrid', 'resize') -->

command: show

Toggles hidden class. Expression must return Boolean.

<div data-bind="some.path__show:value"></div>
<div data-bind="some.path__show:value === 'users'"></div>

command: src

Sets src attribute, targeted for <img. Expression must return String.

<div data-bind="some.path__src:value"></div>

command: strict

This command performs a strict comparing of path. It must be defined without expression.

<div data-bind="myobj.address__strict__html:JSON.stringify(value)"></div>
  • allowed paths myobj or myobj.address
  • another paths like myobj.customer or something else doesn't affect this binder

command: template

Compiles HTML content as a Tangular template. It's defined without expression.

<div data-bind="some.path__template">
    <script type="text/html">
        <div>{{ value.name }}</div>
        <div>{{ value.price | format(2) }}</div>        
    </script>
</div>
  • value represents Tangular model

command: text

Sets a value as the TEXT content (HTML markup will be escaped). Expression must return String.

<div data-bind="some.path__text:value"></div>
<div data-bind="some.path__text:value.toUpperCase()"></div>

command: title

Sets title attribute.

<div data-bind="some.path__title:value"></div>

command: track

Enables a strict path comparison for defined paths separated by comma (use a field name without parent path). Binder will render the content below if the main path object will be changed or specific field (name or price) will be changed.

<div data-bind="some.path__template__track:name,price">
    <script type="text/html">
        <h1>{{ value.name }}</h1>
        <div>Price: {{ value.price | format(2) }} EUR</div>
    </script>
</div>

command: val

Sets value for the input/textarea/select. Expression must return String.

<input data-bind="some.path__val:value" />

command: visible

+v16 sets invisible class to this element if the condition is not valid. invisible class is a part of spa.min.css and it's declaration is .invisible { visibility: hidden; }. Usage:

<div data-bind="some.path__visible:value !== false"></div>

command: .class_name

Toggles .class_name if the expression returns true. You can use multiple .class_name commands.

<div data-bind="some.path__.animate:value > 100"></div>

Multiple:
<div data-bind="some.path__.animate1:value > 100__.animate2:value > 1000"></div>

Types of command expressions

You can use multiple types of command expressions. You need to choose what suits is for you. In most cases value argument contains the real value from a model according to the data-bind path.

Arrow function in the form:

COMMAND:(value,path,jQueryElement)=>value.toUpperCase()

<or>

COMMAND:n=>n.toUpperCase()

Direct value:

COMMAND:value.toUpperCase()

<or>

COMMAND:value

<or>

COMMAND:value > 10

Link to method:

COMMAND:upper_value
  • but function upper_value(value, path, element) must be defined in the window scope

Advanced usage

Good to know

+v16 Most of commands are performend when the element is visible --> in other words: the command show must return true or hide must return false.

If you want to evaluate a command for hidden element then you can extend command by adding ~ before the name of command, for example:

<div data-bind="some.path__~setter:'datagrid','resize'">
    ...
</div>

Linking commands to same expression

You can link commands to same expression with help of + char with spaces on both sides.

<div data-bind="path.to.property__COMMAND + COMMAND + COMMAND:VALUE"></div>
<div data-bind="user.age__visible + .selected:age => age > 18__html:value"></div>

Extending command by adding a selector

You can extend most of commands by adding a custom jQuery selector.

Declaration:
<div data-bind="some.path__html JQUERY_SELECTOR:value"></div>

Usage:
<div data-bind="some.path__html h1:value__show:value">
    <h1></h1>
</div>

Nullable values

Nullable / Undefined values can be handled easily. Just use !COMMAND and evaluating will be performed if the value won't be null or undefined.

<div data-bind="user.name__!html:value.toUpperCase()"></div>

Multiple watchers

You can define multiple data-bind paths in the same HTML element. Paths must be divided by this __|__ phrase. For example:

<div data-bind="path.to.property1__command:expression_|__path.to.property2__command:expression__|__path.to.property3__command:expression"></div>

jComponent scopes

You can use data-bind in jComponent scopes, but you need to defined ? (question mark) on the start of data-bind path. Question mark ? will be replaced for a scope path.

<div data-bind="?.property__html:value"></div>

Good to know:

  • it will work only if the jComponent scope will contain some jComponents

Inline helpers

Data-Binding supports inline helpers:

1. Direct assignment
<div data-bind="form.name --> (value || '').toUpperCase()__html:value"></div>

2. With arrow function
<div data-bind="form.name --> n => (n || '').toUpperCase()__html:value"></div>

3. Plugins
<div data-bind="form.name --> plugin/method(value)__html:value"></div>

Using data-bind in jComponents

The example below will work in component's scope only.

Binds a value according to the data-jc-path attribute.
It works in the component scope only.

<div data-bind="@__COMMAND + COMMAND + COMMAND:VALUE"></div>

Binds a component config.
It works in component scope only.

<div data-bind="@config__COMMAND + COMMAND + COMMAND:VALUE"></div>

Binds a value defined via component.data('property', value).
It works in the component scope only.

<div data-bind="@property__COMMAND + COMMAND + COMMAND:VALUE"></div>

Virtual binder: VBIND

+v16 supports this method. Virtual binder VBIND is a special thing and it can bind data from a custom model which doesn't need to be defined in the window scop. Compiled element doesn't need to be a part of DOM.

  • paths must start with (dot) .path
  • it expects a custom object
// VBIND(template);
var obj = VBIND('<div data-bind=".name__html:value"></div>');

// Sets a model
obj.set({ name: 'Peter' });

// Sets a specific value with path
obj.set('name', 'Peter');

// Removes the binder
obj.remove();

// jQuery element
obj.element.html(); // <div>PETER</div>

// Attachs element into the DOM
$(document.body).append(obj.element);

Virtual binder: VBINDARRAY

+v16 supports this method. VBINDARRAY prepares a template as VBIND object and it renders items/templates very effective according to the array. It's someting similiar like Virtual DOM.

  • paths must start with (dot) .path in the template
  • each VBIND element will contain data-index attribute with the item array index
// VBINDARRAY(template, target_element);
var obj = VBINDARRAY('<div data-bind=".name__html:value"></div>', document.body);
obj.set([{ name: 'Peter' }, { name: 'Anna' }, { name: 'Lucia' }]);