Skip to content

Latest commit

 

History

History
140 lines (105 loc) · 3.99 KB

getting-started.md

File metadata and controls

140 lines (105 loc) · 3.99 KB

Getting started

In KFF, the basic building block of the UI is the view. Despite the name it is more like a component. Its primary goal is to render some part of the UI (genereate a DOM), keep it in sync with javascript state and to react to user interactions by dispatching actions.

Every view is bound to a single DOM element. Views are declared in the data-kff-view attribute of the element. Every view can contain subviews which are nested views bound to descendant elements of the view element.

Every view can also contain bindings. A binding is just a simple way to bind some data to some properties of the DOM element such as the text content, attribute, class, input value etc. Whenever the data change, the DOM is efficiently updated. Some of the bindings are two-way but not in the MVC style – it's more like the flux style. Whenever the value changes as a result of user interaction, an action is dispatched, the state is changed and the whole view tree is rerendered (but only nessesary DOM modifications are applied). Bindings are declared in the data-kff-bind attribute.

Hello World example

<html>
    <body>
        <p data-kff-bind="state.hello:text"></p>
    </body>
</html>
import {View, Cursor} from 'kff';

const stateCursor = new Cursor({
    hello: 'Hello World'
});

const myView = new View({
    scope: {
        state: stateCursor
    }
});
myView.initAll();

A state is a simple javascript object. As you can see, the state is wrapped in something called Cursor. Cursor is a wrapper around the state and allows to point to some property deep in the state object and change it in immutable way. More about cursors see Cursor.

The example above can also be rewritten as follows:

<html>
    <body>
        <p data-kff-bind="hello:text"></p>
    </body>
</html>
import {View, Cursor} from 'kff';

const stateCursor = new Cursor({
    hello: 'Hello World'
});

const helloCursor = stateCursor.refine('hello');

const myView = new View({
    scope: {
        hello: helloCursor
    }
});
myView.initAll();

Here we are creating a subcursor that points to the hello property inside the state.

Array rendering

<html>
    <body>
        <ul data-kff-bind="todos.length:ifnot(0)">
            <li data-kff-bind="todos:each .title:text"></li>
        </ul>
    </body>
</html>
import {View, Cursor} from 'kff';

const stateCursor = new Cursor({
    todos: [
        {
            title: 'first todo'
        },
        {
            title: 'second todo'
        }
    ]
});

const myView = new View({
    scope: {
        todos: stateCursor.refine('todos')
    }
});
myView.initAll();
In the example above, you can see some new stuff:
  • todos.length:ifnot(0) - todos.length obviously gets the length of the array. The ifnot binder removes the ul element from the DOM when the length is zero.
  • todos:each is a collection binder. It will generate a new li element for every item of the todo array.
Note that:
  • Multiple bindings can be used in a single data-kff-bind attribute separated by a space.
  • KFF doesn't use any nonstandard html-invalid syntax nor mustache-like templating syntax, everything is inside data-kff- attributes

Two way "data binding"

<html>
    <body>
    	<p><input type="text" data-kff-bind="name:val" placeholder="Your name…"></p>
        <p data-kff-bind="name:if">Hello, <span data-kff-bind="name:text"></span></p>
    </body>
</html>
import {View, Cursor} from 'kff';

const myView = new View({
    scope: {
        name: new Cursor(null);
    }
});
myView.initAll();
Notes:
  • You can create a Cursor of not only an object, but also of a primitive value, even of null. It's not a common case but it's perfectly possible.
  • Whenever you type in the input, the default set action is dispatched and the entire view is refreshed with the new state.

More about creating custom Views

More about Data binding