v1.9.1
The easiest framework in the Universe
<input class="in" type="text">
<output class="out"></output>

<script src="matreshka.min.js"></script>
<script>
var app = new Matreshka();
app.bindNode('x', '.in, .out');
app.x = 'The easiest framework in the Universe';
</script>

Download Github

Who's helping to the project?

The main sponsor
Matreshka
% slower
React
% slower
Knockout
% slower
Angular


Based on this benchmark

And check out DMBON test

Special thanks to...

Alexander Kolodko for awesome logo.

Chris Opler for $600 donation.

Introduction

Matreshka is a framework for massive and endlessly extending single page applications (within the Universe, of course), written in JavaScript. It allows you to build program architecture so that neither your team nor you can get confused in plentiful entities, logic described in HTML files, numerous restrictions of other frameworks and incomprehensible abstractions.

Two-way data binding is implemented by bindNode method only and it does not require to change HTML, adding weird syntactic constructions. Having set a few rules, a programmer can continue to work with data and forget about a state of visible part of an application.

The order is not important, you can declare binders after complete implementation of logic which is responsible for data.

In Matreshka collections are represented by Matreshka.Array class, whose instances themselves render HTML while adding, deleting and changing its items. You can say that the framework X renders items of an array too, but in Matreshka this issue is resolved very simply and elegantly.

Additionally, Matreshka is a framework which is very easy for understanding. Any developer, from a beginner who can write simple things in JavaScript to an experienced ninja, will handle it without any problems.

Getting started

All popular frameworks include lots of convenient and interesting functions. The problem is that it is difficult for a beginner to understand where to start his training. A great number of functional possibilities of a given framework leads us to the reasonable question "Hey, do I have to learn all that?"

This issue has been resolved in this documentation. We have split up the API into three parts.

The first level - the most important stuff

After you've learned the most important API parts you can hardily start doing fantastic things. Classes, methods and properties marked with need to be learned primarily.

The second level - recommended to learn

If you already know the quick-start basics, you can look at other methods and properties of Matreshka.

The third level - other methods and properties

We've hidden rarely used parts (Matreshka API is really rich). If you want to know everything about Matreshka, turn on "Advanced mode" checkbox from the menu.

Warning. If you open a link to a method or a property of the third level of importance, the "Advanced mode" is turned on automatically.

This page can't do without the fantastic possibilities of HTML5. It is available offline for any device whether it is your computer or a mobile phone.

Chrome for Android: enter the menu and click "Add to home screen"

Safari for iOS: tap on the "Action" icon and choose "Add to Home Screen"

Any other devices: just bookmark the page

Now the documentation to Matreshka can be read without the Internet connection. If the page lags (noticed in Android 4.2), switch over to the mode "One By One".

Hello World!

Writing your first application is very easy. You should:

1. Create an HTML file with the following content

<!DOCTYPE html>
<html>
    <head>
        <title>My first Matreshka application</title>
    </head>
    <body>
        <input type="text" class="my-input">
        <div class="my-output"></div>
        <script src="http://cdn.jsdelivr.net/matreshka/latest/matreshka.min.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>

2. Write your first class which inherits Matreshka creating the file js/app.js

var Application = Class({
    'extends': Matreshka,
    constructor: function() {

        // bind the property x and the text field
        this.bindNode('x', '.my-input');

        // bind the property x and the ".my-output" block
        this.bindNode('x', '.my-output', {
            setValue: function(v) {
                this.innerHTML = v;
            }
        });

        // if the property "х" has changed,
        // inform about it in the console
        this.on('change:x', function() {
            console.log('x changed to ' + this.x);
        });
    }
});

var app = new Application();

3. That's it!

Now you can open the developer's console (by pressing F12) and write:

app.x = 'Hello World!';

Cool, isn't it? Now you can work with the properties directly without any weird encapsulations.

Matreshka uses the object-oriented approach based on classes which are acknowledged to be the best in most programming languages such as Python, C#, Java and many others. This way allows to easily change over to new possibilities of JavaScript syntax described in the ECMAScript 2015 specs and supported by Matreshka out of the box. Babel lets us make use of the cool new generation JS syntax today.

class Application extends Matreshka {
    constructor() {
        this.bindNode('x', '.my-input');
        this.bindNode('x', '.my-output', {
            setValue(v) {
                this.innerHTML = v;
            }
        });
        this.on('change:x', () =>
            console.log('x changed to ' + this.x));
    }
}

Live example (click on "Run with JS", to launch it)

Links

How to include?

Matreshka is independent framework that requires no dependencies. But you can use jQuery or Zepto as a library which will be used by Matreshka for DOM manipulations. If jQuery or Zepto isn't found on a page, the tiny library called bQuery will be used instead.

<script src="js/matreshka.min.js"></script>

Besides, Matreshka supports AMD (require.js or almond)

require(['path/to/matreshka'], function(Matreshka) {
    //...
});

Import via ECMAScript 2015 (using Babel)

import Matreshka from 'path/to/matreshka';

Class Matreshka

The class Matreshka is a core of the Matreshka.js framework which is inherited by Matreshka.Array, Matreshka.Object and every class of the application you create. It contains the main functionality of the framework, among which there are some very useful functions, such as mediators, dependencies, two-way data binding, an event engine, etc. The inheritance of this class, the same as the inheritance of any other class, is carried out with the help of the Class function.

This class, (like Matreshka.Array and Matreshka.Object), usually isn't used directly. Instead, it is inherited by the classes that you create. Therefore, the examples to the properties and methods in this documentation, as a rule, will be given with the use of this keyword.

Links

Examples

Creating of an instance

var mk = new Matreshka();

You can use MK variable instead of Matreshka

var mk = new MK();

Inheritance

var MyClass = Class({
	'extends': Matreshka,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

Matreshka uses prototypes for implementing the inheritance. The Class function just brings in some syntactic sugar. That's why you can use any other way of the inheritance you like, for example, using classes from ECMAScript 2015

class MyClass extends Matreshka {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}
ASK A QUESTION

Matreshka#bindNode(key, node, binder, eventOptions) matreshka

Binds a property of an object to HTML node, implementing two-way data binding

Matreshka#bindNode is the only method of the Matreshka class which is responsible for changing DOM (except array renderer). It creates a bridge between value of a property and state of HTML node on the page: from a simple input to a complicated widget (the complexity of elements is unlimited). bindNodecan be truly regarded as the main method of the framework. After using this method, it isn't necessary to monitor the synchronizations between model and view.

The method acepts three arguments: a property name (key), HTML node (or a selector) and a binding rule (a binder). In its turn, a binder is an ordinary object and it can have the following properties: on, getValue, setValue, initialize (Read more here: binder). All the four properties are optional. It also allows to declare one-way data bindings (any direction).

The bindNode method supports the many-to-many bindings. Several elements can be bound to one property and several properties can be bound to one element, including ones from different instances of various classes.

this.bindNode('myKey', '.my-element', {
    on: 'click',
    getValue: function() { ... },
    setValue: function() { ... }
});

For example, you want to bind a property of an object to a input[type="checkbox"] node:

this.bindNode('myKey', '.my-checkbox', {
    // when is element state changed?
    // - after 'click' event
    on: 'click',
    // how to extract element state?
    // - return 'checked' value
    getValue: function() {
        return this.checked;
    },
    // how to set element state?
    // - set 'checked' value
    setValue: function(v) {
        this.checked = !!v;
    }
});

After binding is declared, you can set value of an object property in your most habitual way and HTML node (in this case, a checkbox) will change its state in no time. After clicking on the checkbox, the property value will be changed to the corresponding one as well.

// sets checked = true
this.myKey = true;

If a property value of class instance is not given, after a binding Matreshka will try to extract its value from the HTML node using getValue. This behavior can be cancelled by passing the assignDefaultValue: false property to event object.

this.bindNode('myKey', '.my-element', binder, {
    assignDefaultValue: false
});

More complicated example: binding object property to jQuery UI widget

<div class="my-slider"></div>
this.bindNode('myKey', '.my-slider', {
    // when is element state changed?
    // - after 'slide' event
    on: 'slide',
    // how to extract element state?
    // - return 'value' of the widget
    getValue: function() {
        return $(this).slider('option', 'value');
    },
    // how to set element state?
    // - set 'value'
    setValue: function(v) {
        $(this).slider('option', 'value', v);
    },
    // how to initialize the widget?
    // you can initialize the slider in any way,
    // but 'initialize' function provides some syntactic sugar
    initialize: function() {
        $(this).slider({min: 0, max: 100});
    }
});
// will set the slider value 42
this.myKey = 42;

It looks easy but you may ask a question: "What should I do to avoid writing these rules every time?". The question is absolutely correct. Indeed, there can be a lot of elements of the same type on the page: text fields, drop down menus, new fields from the HTML5 specification as well as third party widgets (see the example above).

As observed in this documentation, the third argument is not obligatory for the ones of the Matreshka#bindNode method (see below). This problem is solved by the Matreshka.defaultBinders array which contains functions checking an HTML node against a set of rules. You get an opportunity to reduce your code a great deal, putting binding rules into a separate part of your code and to use a syntax for binding without the third argument:

this.bindNode('myKey', '.my-element');

How to do it? You should add the function checking your element against a set of rules to the beginning of the Matreshka.defaultBinders array. The example below can be used as a template for creating your default binder.

// add the binder to the collection of binders
// it is necessary to keep the possibility of overriding
Matreshka.binders.checkbox = function() {
    return {
        on: 'click',
        getValue: function() {
            return this.checked;
        },
        setValue: function(v) {
            this.checked = !!v;
        }
    }
};

// the unshift method adds the function
// to the beginning of the Matreshka.defaultBinders array
Matreshka.defaultBinders.unshift(function(node) {
    // check if the element is a checkbox
    if(node.tagName == 'INPUT' && node.type == 'checkbox') {
        // if checking is OK, return a new binder
        return Matreshka.binders.checkbox();
    }
});
this.bindNode('myKey', '.my-checkbox');
this.myKey = true;

What should you do if you need to pass arguments for initializing some plug-in or a widget? It is a piece of cake: you can do with adding the binder to the Matreshka.binders collection without creating a function for Matreshka.defaultBinders.

Matreshka.binders.uiSlider = function(min, max) {
    return {
        on: 'slide',
        getValue: function() {
            return $(this).slider('option', 'value');
        },
        setValue: function(v) {
            $(this).slider('option', 'value', v);
        },
        initialize: function() {
            $(this).slider({min: min, max: max});
        }
    }
};
this.bindNode('myKey1', '.my-slider1', Matreshka.binders.uiSlider(0, 100));
this.bindNode('myKey2', '.my-slider2', Matreshka.binders.uiSlider(1, 1000));
this.myKey1 = 42;
this.myKey2 = 999;

DOM changes are happening synchronously after every change of a property. You can "debounce" all changes passing debounce: true property to eventOptions argument. Look at Matreshka.debounce

To change this

Изменения DOM происходят синхронно, сразу после изменения свойства. Для того, чтоб DOM менялся после небольшой задержки только один раз, несмотря на то, как часто меняется свойство, передайте в аргумент eventOptions свойство debounce: true.

Matreshka.defaultBinders OOB, starting with the version 0.3, has a support for all form elements without any exception: select (including multiple), textarea, output, input (including all types from the specification of HTML5: text, checkbox, radio, range, number, date, search, time, datetime, datetime-local, color and others). That means it is not necessary to designate a binder for standard elements.

<input type="color" class="my-color-input">
this.bindNode('myColor', '.my-color-input');
this.myColor = '#66bb6a';

Besides, after the binding, a new non-standard :bound(KEY) CSS selector is available for you.

this.bindNode('myKey', '.my-element');

// will find the element '.my-inner-element' inside '.my-element'
this.bindNode('myAnotherKey', ':bound(myKey) .my-inner-element');

And the syntax of possible event names is extended:

this.bindNode('myKey', '.my-element');

// will handle the click on the .my-element element
this.on('click::myKey', function() { ... });

// will handle the click on the .my-element .my-inner-element
this.on('click::myKey(.my-inner-element)', function() { ... });

The creation of a sandbox

Matreshka#bindNode can associate a class instance with the "main" HTML element on the page creating so-called sandbox. It is necessary to limit the instance influence on HTML nodes contained in another sandbox (i. e. inside another HTML node). A special property 'sandbox' is used for binding a sandbox.

<div class="my-sandbox">
    <!-- your HTML code -->
</div>
this.bindNode('sandbox', '.my-sandbox');

The definition of the sandbox adds lots of conveniences for you. For example:

Also you can try Matreshka#bindSandbox which does the same thing but requires only one argument.

// declare a sandbox
this.bindNode('sandbox', '.my-sandbox');

// .my-element is being searched for in the sandbox
this.bindNode('myKey', ':sandbox .my-element');

// it is not required to specify a key
// for the delegated events inside a sandbox
this.on('click::(.my-button)', function() { ... });

// will print a sandbox element into the console
console.log(this.$bound());

// will put the .inner-node element
// which is inside the sandbox into the console
console.log(this.$('.inner-node'));

Deep binding

Since version 1.1, the bindNode method supports the new feature called "deep binding". The method can bind DOM node to some property of nested object. For example, you have some nested object:

this.a = {b: {c: {d: 42}}};

And you want to bind some DOM node to d. The only thing you need is to pass a path to needed property and Matreshka will listen all changes throughout a tree of nested object by breaking a binding then re-creating it again:

this.bindNode('a.b.c.d', '.my-node');

When some changes appear in the nested tree bindNode catches them and recreates binding again.

this.a.b = {c: {d: 41}};

This behavior is cancelable. You can set deep: false property for eventOptions object to ignore dot in a property name.

Это поведение можно отменить, передав свойство deep: false в объект события (eventOptions), тогда точка в имени свойства будет проигнорирована.

Returns matreshka - self

Fires bind bind:KEY

Arguments

Name Type Details
key string matreshka

A key (a property name)

node string node $nodes

An HTML element which must be bound to a key

binder optional binder

A binder containing the following properties: on - which event must happen to an HTML node, informing that a user has changed something (for example, keyup or click), getValue - how to get a value from an HTML node, setValue - how to set a new value to a node and initialize - a function which is executed once after the initialization of binding. You can get more detailed information about binders in their documentation: see binder.

eventOptions optional eventOptions

An event object which accepts "silent" (don't fire "bind" and "bind:KEY"), "assignDefaultValue" (etract current node value), "debounce" (optimize DOM changes), "deep" (use "deep binding" or ignore a dot in a property name) or some custom data for event handlers.

Links

Examples

A custom checkbox. This example demonstrates the creation of custom element whose "checked" class is changed after clicking on it.

this.bindNode('myKey', '.custom-checkbox', {
	on: 'click',
	getValue: function() {
		return $(this).hasClass('checked');
	},
	setValue: function(v) {
		$(this).toggleClass('checked', !!v);
	},
	// initialize element behavior
	// the presence of 'checked' class name is changed after clicking on the element
	initialize: function() {
		$(this).on('click', function() {
			$(this).toggleClass('checked');
		});
	}
});

A custom checkbox 2. This example is the same as the previous one but it uses Matreshka#defaultBinders, and checks the element if the custom-checkbox. class is present. If checking is OK, it returns the binder.

// add the binder to the 'binders' namespace
Matreshka.binders.customCheckbox = function() {
	return {
		on: 'click',
		getValue: function() {
			return $(this).hasClass('checked');
		},
		setValue: function(v) {
			$(this).toggleClass('checked', !!v);
		},
		initialize: function() {
			$(this).on('click', function() {
				$(this).toggleClass('checked');
			});
		}
	}
};

MK.defaultBinders.unshift(function(element) {
	// check if the element has the "custom-checkbox" class
	if($(element).hasClass('custom-checkbox')) {
		// if checking is OK, return a new binder
		return Matreshka.binders.customCheckbox();
	}
});

this.bindNode('myKey', '.my-custom-checkbox');

The "bind" event which is fired after any binding

this.on('bind', function() {
	alert('ok!');
});

this.bindNode('myKey', '.my-element'); // alerts "ok!"

The "bind:KEY" event which is fired after binding of specific property to HTML node

this.on('bind:myKey', function() {
	alert('ok!');
});

this.bindNode('myKey', '.my-element'); // alerts "ok!"

DOM event overriding for default binder. For example, we want to bind input[type="text"] to a property. By default, the standard binder contains "on" property with the "input" value for this kind of node. It means that a value of an instance property and node state will be synchronized when a user releases a key of the keyboard or pastes text from clipboard. In case if you want synchronization to be performed after the "blur" DOM event, you will have to pass the object containing the only "on" property as the third argument. This object will join the default binder, having retained getValue and setValue values.

this.bindNode('myKey', '.my-input', {on: 'blur'});

If an element is not found, the "Bound element is missing" exception is thrown. In order to avoid the error, use the Matreshka#bindOptionalNode method

var $el = $();
this.bindNode('x', $el); // an error because $el is empty

Synchronization of a property value and HTML contents of a node

this.bindNode('myKey', '.my-element', {
	setValue: function(v) {
		this.innerHTML = v;
	}
});

// it can be done easier
this.bindNode('myKey', '.my-element', MK.binders.html());
ASK A QUESTION

Matreshka#bindNode(keyElementPairs, binder, eventOptions)

Alternative syntax: "key-element" pairs

In the Matreshka#bindNode method an object with the key-element pairs can be passed to avoid multiple invocation of the method and reduce the code.

Arguments

Name Type Details
keyElementPairs object

(see the example)

binder optional binder

(see above)

eventOptions optional eventOptions

(see above)

Examples

this.bindNode({
	myKey1: '.custom-checkbox',
	myKey2: 'textarea'
});

Starting version 1.1 the syntax of the method is extended: you can pass an array with node and binder instead of just a node

this.bindNode({
	myKey1: ['.custom-checkbox', MK.binders.customCheckbox()],
	myKey2: 'textarea',
	myKey3: ['.my-node', {
		setValue: function(v) {
			// do something
		}
	}]
});
ASK A QUESTION

Matreshka#bindNode(setOfArguments, eventOptions)

Alternative syntax: "heap of arguments"

Another syntax for the Matreshka#bindNode method. This way may seem unattractive but sometimes you have need of binding lots of nodes to different properties at one operation. With such a syntax you can assign definite binders to some variable and then easily delete all at once using Matreshka#unbindNode.

Arguments

Name Type Details
setOfArguments array

The array of arrays (see the example)

eventOptions optional eventOptions

(see above)

Examples

this.bindNode([
	[{
		myKey1: '.my-element1',
		myKey2: '.my-element2'
	}],
	[{
		myKey3: '.my-element3',
		myKey4: '.my-element4'
	}, {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... }
	}],
	[{
		myKey5: '.my-element5',
		myKey6: '.my-element6'
	}, {
		on: 'somethingelse',
		getValue: function() { ... },
		setValue: function() { ... }
	}]
]);
ASK A QUESTION

Matreshka#bindSandbox(node, eventOptions)

Available since 1.5.

Binds a sandbox

Optimized method for quick "sandbox" declaration.

Fires bind bind:sandbox

Arguments

Name Type Details
node string node $node

A sandbox DOM node

eventOptions optional eventOptions

Event object ("silent" key disables firing the events "unbind" and "unbind:KEY")

Links

Examples

this.bindSandbox('.my-element');
ASK A QUESTION

Matreshka#bound(key) node null

Returns the first bound element or null

Returns node null - The bound element

Arguments

Name Type Details
key optional string

A key of a property (or the list of the keys separated by spaces), which bound nodes we need to get. If no arguments are passed the method returns a sandbox.

Examples

this.bindNode('myKey', '.my-element');
this.bound('mykey'); // will return $('.my-element')[0]

Getting sandbox node (you can use Matreshka#sandbox property instead)

this.bindNode('sandbox', '.app');
this.bound(); // will return $('.app')[0]
ASK A QUESTION

Matreshka#boundAll(key) $nodes

Returns a collection of bound nodes by given key

Returns $nodes - Bound nodes

Arguments

Name Type Details
key optional string

The key of a property (or a list of keys separated by spaces), which bound elements we want to get. If no arguments are passed the method returns a sandbox.

Examples

this.bindNode('myKey', '.my-element');
this.boundAll('myKey'); // will return $('.my-element')

Getting sandbox node (you can use Matreshka#$sandbox property instead)

this.bindNode('sandbox', '.app');
this.boundAll(); // will return $('.app')
ASK A QUESTION

Matreshka#define(key, descriptor) matreshka

Overrides a property descriptor completely using Object.defineProperty

Use this method only when you know what you are doing.

Returns matreshka - self

Arguments

Name Type Details
key string

A key

descriptor function

A descriptor

Examples

this.define('myKey', {
	get: function() { ... }
	set: function() { ... }
});
ASK A QUESTION

Matreshka#define(keyObjectPairs) matreshka

Alternative "key-descriptor" syntax for the Matreshka#define method

The work of the method is very similar to Object.defineProperties

Returns matreshka - self

Arguments

Name Type Details
keyObjectPairs object

An object containing key-descriptor pairs

Examples

this.define({
	myKey1: {
		get: function() { ... }
		set: function() { ... }
	},
	myKey2: {
		get: function() { ... }
		set: function() { ... }
	}
});
ASK A QUESTION

Matreshka#defineGetter(key, getter)

Defines custom getter for a property

This method allows to define a getter using the native Object.defineProperty method. The returned property value is calculated on every accessing the property, that is why, from viewpoint of performance, the most preferred method is Matreshka#linkProps.

Arguments

Name Type Details
key string

A key property which the getter is set for

getter function

A getter function

Examples

this.defineGetter('myKey', function() {
	// a function can return any calculated value
	return 42;
});
ASK A QUESTION

Matreshka#defineSetter(key, setter)

Defines a custom setter for a property

This method allows to define a setter using the Object.defineProperty. While using this method you should remember that it overrides a setter which has been built in by Matreshka and in this way it disables the opportunity to catch events like change:KEY. Use this method if you are 100% sure what you are doing. The Matreshka#on and Matreshka#mediate methods are safe from viewpoint of stability of the application you create so it is better to use them.

Arguments

Name Type Details
key string

A key which the setter is required to be defined for

setter function

A setter function

Examples

this.defineSetter('mykey', function(v) {
	alert(v);
});
ASK A QUESTION

Matreshka#delay(f, delay, thisArg) matreshka

Available since 0.3.

Calls given function after timed delay

The work of the method is very similar to setTimeout. A current instance or a passed object is taken as a context.

Returns matreshka - self

Arguments

0
Name Type Details
f function

A function which must be called after the timer has expired

delay optional number

A delay in milliseconds

thisArg optional object

A context

Links

Examples

this.on('change:x', function() {
	alert(this.x); // 1 ... 2
});

this.delay(function() {
	this.x = 2;
}, 100);

this.x = 1;
ASK A QUESTION

Matreshka#linkProps(targetKeys, sourceKeys, handler=function(v){return v}, eventOptions)

Available since 0.1.

Creates a dependency of one property value on values of others

The linkProps method creates a dependency of a property value (target property, the first argument) on values of other properties (source properties, the second argument). The method is protected from circular references (for example, a depends on b, b depends on c and c depends on a) and if there is a calculation error, it does not block the page and does not throw an exception about the stack over-flow.

In Matreshka 1.5 the setOnInit (4th argument) is replaced by eventOptions which gives more useful features to the method.

Passing data to a property-change event handler and special flags

You can pass some data to change:KEY event handler via eventOptions.

this.on('change:a', function(evt) {
    alert(evt.foo); // 'bar'
});

this.linkProps('a', 'b c', function(b, c) {
    return b + c;
}, {
    foo: 'bar'
});

Besides, eventOptions allows you to pass special flags (eg. silent: true)

this.on('change:a', function(evt) {
    alert('foo');
});

this.linkProps('a', 'b c', function(b, c) {
    return b + c;
}, {
    silent: true
});

this.b = 1;

In the example above when linkProps mechanism changes a source property, event handler isn't called.

If the target property is changed in some other way eg via direct assignment (this.a = 42) then change:KEY handler still will be called.

The full list of supported flags you can find at Matreshka#set.

Immediate property calculation on linkProps call

By default, a property will be calculated immediately after linkProps is called.

var handler = function(b, c) {
    return b + c;
};

this.b = 1;
this.c = 2;
this.linkProps('a', 'b c', handler);
alert(this.a); // 3

To cancel this behavior pass setOnInit: false flag into the eventOptions object. This flag is helpful when source properties aren't set yet and you don't want to get a "bad" value of the target property. In the example below linkProps is calculating a sum of b and c as undefined + undefined and a becomes NaN.

var handler = function(b, c) {
    return b + c;
};

this.linkProps('a', 'b c', handler);
alert(this.a); // NaN
this.linkProps('a', 'b c', handler, {
    setOnInit: false // everything is OK now
});

Immediate calculation

A process of recalculation of a target property is instantaneous and synchronous. That means every change of source property triggers linkProps mechanism immediately. Look at this example:

var handler = function(b, c) {return b + c;};

this.linkProps('a', 'b c', handler);
this.b = 1;
this.c = 2;

The handler is going to be called thrice. The first call is on linkProps call (if setOnInit isn't used), the second call is on b assignment and the third call is on c assignment. This behavior is based on one idea: "all reactions on every change have to occur consistently and predictably". If you want to optimize this behavior pass debounce: true property to the eventOptions object. Look at the Matreshka.debounce.

var handler = function(b, c) {
    return b + c;
};

this.linkProps('a', 'b c', handler, {
    debounce: true
});
this.b = 1;
this.c = 2;

In the example above the handler will be called only once after tiny delay.

Arguments

Name Default Type Details
targetKeys string array

A property (properties) which depends on other ones

sourceKeys string array

Which properties the desired property (properties) is depended on

handler optional function(v){return v} function

A function which returns a new value

eventOptions optional object

An object which can contain some special flags or data for change:KEY handler (see above)

Examples

this.linkProps('greeting', 'name', function() {
	return 'Hello, ' + this.name + '!';
});

this.name = 'Joe';

alert(this.greeting); // 'Hello, Joe!'

A complicated example: the calculation of the rectangle perimeter with two sides known (and the calculation of the sides with the perimeter known). As you see, linkProps can be used for the solution of mathematical problems as well, where every member of equation can be used as the unknown

this.a = 3;

this.b = 4;

this.linkProps('p', 'a b', function(a, b) {
	return (a + b) * 2;
});

this.linkProps('a', 'p b', function(p, b) {
	return p/2 - b;
});

this.linkProps('b', 'p a', function(p, a) {
	return p/2 - a;
});

alert(this.p); // 14

this.on('change:p', function() {
	alert('The perimeter has been changed and equals ' + this.p);
});

this.a = 5; // alerts "The perimeter has been changed and equals 18"

Starting the v1.1, you can pass a path to target property

this.a = {b: {c: 21}};

this.linkProps('x', 'a.b.c', function(c) {
	return c * 2;
});

alert(this.x); //42
ASK A QUESTION

Matreshka#linkProps(targetKeys, instancesAndKeys, handler=function(v){return v}, eventOptions)

Available since 0.2.

An additional possibility of the Matreshka#linkProps method: a dependency on property values of other instances

Arguments

Name Default Type Details
targetKeys string array

A property (properties) which depends on other ones

instancesAndKeys array

An array which contains instances (even elements) and their keys (uneven elements), which a desired property (properties) is depended on. This syntax which may seem strange is the consequence of JavaScript syntax constraints.

handler optional function(v){return v} function

A function which returns a new value

eventOptions optional object

An object which can contain some special flags or data for change:KEY handler (see above)

Examples

The sum property is a sum of a and b values of other instances and it is calculated every time on their changing

anotherInstance1.a = 2;

anotherInstance2.b = 3;

this.linkProps('sum', [
	anotherInstance1, 'a',
	anotherInstance2, 'b'
], function(a, b) {
	return a + b;
});

alert(this.sum); // 5

this.on('change:sum', function() {
	alert('this.sum equals ' + this.sum);
});

anotherInstance1.a = 5; // "this.sum equals 8"
ASK A QUESTION

Matreshka#mediate(key, mediator)

Available since 0.1.

Transforms property value on its changing

This method is used for transforming the property value on its changing. For example, you want the property value to be always either of a certain type or an integer value, or to be no less than zero and no more than a hundred etc.

Arguments

Name Type Details
key string array

A key or an array of keys or a list of keys which are separated by spaces

mediator function

A function-mediator which returns a new value

Examples

this.mediate('x', function(value) {
	return String(value);
});

this.x = 1;

alert(typeof this.x); // "string"

A list of keys which are separated by spaces

this.mediate('x y', function(value) {
	return String(value);
});

An array of keys

this.mediate(['x', 'y'], function(value) {
	return String(value);
});
ASK A QUESTION

Matreshka#mediate(keyMediatorPairs)

Available since 0.1.

Alternative syntax of the Matreshka#mediate method which accepts "key-mediator" object as an argument

Arguments

Name Type Details
keyMediatorPairs object

An object with key-mediator properties

Examples

this.mediate({
	x: String,
	y: Number,
	z: Boolean
});
this.x = 1;
this.y = 2;
this.z = 3;
alert(typeof this.x); // "string"
alert(typeof this.y); // "number"
alert(typeof this.z); // "boolean"

A list of keys which are separated by spaces

this.mediate({
	'u v': String,
	'w x': Number,
	'y z': Boolean
});
ASK A QUESTION

Matreshka#off(names, callback, context) matreshka

Deletes an event handler

It deletes a handler which has been created before. All the three arguments are optional. You can delete both all the events (without passing any argument) and separate ones (having passed only the event name, the event name and the handler, the event name and the handler and the context)

Returns matreshka - self

Fires removeevent removeevent:NAME

Arguments

Name Type Details
names optional eventNames

A list of event names which are separated by spaces (for example, "change:x ajaxcomplete change:y")

callback optional eventHandler

A function-handler

context optional object

A context

Links

Examples

this.off('change:x bind');

The deletion of all events

this.off();

The deletion of an event with definite handler

var handler = function() {
	//...
}
this.on('change:x', handler);
this.off('change:x', handler);

The deletion of an event with definite context

var object = {};
this.on('change:x', handler, object);
this.off('change:x', handler, object);
ASK A QUESTION

Matreshka#on(names, callback, triggerOnInit, context) matreshka

Adds an event handler

The Matreshka#on method adds an event handler for an instance of the Matreshka class. Refer to the complete list of possible events with the description here: eventNames.

Returns matreshka - self

Fires addevent addevent:NAME

Arguments

false
Name Type Details
names eventNames

An event name or some names which are separated by a space (for example, "change:x ajaxcomplete change:y")

callback eventHandler

A function which is caused by the event

triggerOnInit optional boolean

If triggerOnInit argument equals true, the handler will be called immediately after event initialization.

context optional object

A context of the handler. In other words, this when called callback

Links

Examples

this.on('foo', function() {
	alert('Custom Event is fired');
});

this.trigger('foo');

Passing a context

this.on('foo', function() {
	alert(this.a); // 5
}, {a: 5});

this.trigger('foo', 'Hello world');

Calling a handler immediately after event initialization

// Displays "bar" at once and waits for a firing of "foo" event
this.on('foo', function() {
	alert('bar');
}, true);
ASK A QUESTION

Matreshka#on(evtnameHandlerObject, triggerOnInit, context) matreshka

Available since 1.1.

Alternative syntax: "eventname-handler" pairs

In the Matreshka#on method the object with the key-element pairs can be passed to avoid multiple invocation of the method and reduce your code.

Returns matreshka - self

Arguments

false
Name Type Details
evtnameHandlerObject object

An object where keys are event names and values are event handlers

triggerOnInit optional boolean

If triggerOnInit argument equals true, all handlers will be called immediately after event initialization.

context optional object

A context of the handler

Examples

this.on({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});

ECMAScript 2015

this.on({
	'custom': evt => ...,
	'click::x': evt => ...,
	'change:y': evt => ...,
});
ASK A QUESTION

Matreshka#onDebounce(names, callback, debounceDelay, triggerOnInit, context) matreshka

Adds an event handler which is called only once during a definite period of time

The method allows to add an event handler to an instance of the Matreshka class, debouncing the handler. Callback function can be called only once during a definite period of time. As to the rest the method works the same as Matreshka#on.

Returns matreshka - self

Fires addevent addevent:NAME

Arguments

0 false
Name Type Details
names eventNames

An event name or some names which are separated by a space (for example, "change:x ajaxcomplete change:y").

callback eventHandler

A handler which is caused by an event

debounceDelay optional number

A delay

triggerOnInit optional boolean

If triggerOnInit argument equals true, the handler will be called immediately after event initialization.

context optional object

A context of a handler. In other words, this when called callback

Links

Examples

this.onDebounce('change:x', function() {
	alert('x = ' + this.x); // x = 100
}, 300);

this.x = 1;

for(var i = 0; i < 100; i++) {
	this.x++;
}
ASK A QUESTION

Matreshka#onDebounce(evtnameHandlerObject, debounceDelay, triggerOnInit, context) matreshka

Available since 1.1.

Alternative syntax: "eventname-handler" pairs

Returns matreshka - self

Arguments

0 false
Name Type Details
evtnameHandlerObject object

An object where keys are event names and values are event handlers

debounceDelay optional number

A delay

triggerOnInit optional boolean

If triggerOnInit argument equals true, all handlers will be called immediately after event initialization

context optional object

A context of a handler

Links

Examples

this.onDebounce({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});
ASK A QUESTION

Matreshka#once(names, callback, context) matreshka

Adds an event handler which can be called only once

The method works the same as Matreshka#on but the passing handler can be called only once. Note the method lacks the triggerOnInit argument.

Returns matreshka - self

Fires addevent addevent:NAME

Arguments

Name Type Details
names eventNames

An event name or some names which are separated by a space (for example, "change:x ajaxcomplete change:y")

callback eventHandler

A handler which is caused by an event

context optional object

A context of a handler

Links

Examples

this.x = 1;

this.once('change:x', function() {
	alert('x is changed');
});

this.x = 2; // displays 'x is changed'

this.x = 3; // does nothing
ASK A QUESTION

Matreshka#once(evtnameHandlerObject, context) matreshka

Available since 1.1.

Alternative syntax: "eventname-handler" pairs

Returns matreshka - self

Arguments

Name Type Details
evtnameHandlerObject object

An object where keys are event names and values are event handlers

context optional object

A context of a handler

Links

Examples

this.once({
	'custom': function(evt) { ... },
	'click::x': function(evt) { ... },
	'change:y': function(evt) { ... }
});
ASK A QUESTION

Matreshka#parseBindings(node) $nodes

Available since 1.1.

Parses DOM tree, declaring property bindings which are double braced.

Starting with 1.1 version, Matreshka includes a simple DOM parser that handles double braced syntactic constructions. parseBindings method receives one optional argument: HTML string, DOM node or selector corresponding to DOM node. If argument isn’t set, parser handles a sandbox (see Matreshka#bindNode).

As the method is DOM template engine (and not HTML-replace parser), all child DOM nodes of the passed element remain in their same state (for example, DOM events aren’t erased).

The supported syntax

  1. HTML binding

    <!--
    will create DOM node in place of {{user.name}}
    and will bind name property from user object to this node
    JS: this.user = {name: 'Joe'}
    -->
    <span>Hello, {{user.name}}</span>
  2. Binding form elements.

    <!--
    will bind "x" instance property to a text field (two-way data binding)
    JS: this.x = 'some value';
    -->
    <input type="text" value="{{x}}">
    <!--
    For binding textarea and select you should use value attribute
    -->
    <textarea value="{{x}}"></textarea>
    <select value="{{x}}">...</select>
    <!--
    will bind "x" instance property to a checkbox (two-way data binding)
    JS: this.x = true;
    -->
    <input type="checkbox" checked="{{x}}">
  3. Attributes binding.

    <!--
    href attribute value will depend on "category"
    and "someObject.page" value (one-way data binding)
    JS:
    this.category = 'matreshka';
    this.someObject = {page: 42}
    -->
    <a href="http://example.com/{{category}}/{{someObject.page}}">A link</a>
    <!--
    The result:
    <a href="http://example.com/matreshka/42">A link</a>
    -->

Why do we need this method?

In case if you develop a large form with standard HTML5 fields, the method will help you save time on declaring numerous bindings. Besides, parseBindings is useful in case of creating a very simple collection which doesn’t require implementation of a complicated model.

Is it compatible with Matreshka ideology ("all logic must be included into JavaScript file")?

Yes, no cycles, conditional operators or any other logic are supported in the parser. Only declaration of simple bindings is available for a developer using `parseBindings.

Performance

The method works a little slower than manual declaration of bindings with Matreshka#bindNode method. You should bear that in mind while creating applications with very strict performance requirements. The speed decreases a little only during the process of binding. As for the rest, bindings work as fast as with Matreshka#bindNode.

If you want to use something else instead of braces look at Matreshka.parserBrackets

Returns $nodes - A collection of DOM nodes (usually contained single node), which is passed to the method as an argument; or a sandbox, in case when there are no arguments are passed.

Arguments

Name Type Details
node optional string node $nodes

HTML string, selector, DOM node or collection of DOM nodes

Examples

Parsing of given node

this.parseBindings(node);

Parsing of nodes matching given selector

this.parseBindings('.my-node');

HTML string parsing

var $node = this.parseBindings('<h3>Hello, {{name}}</h3>');
this.name = 'Arthur Philip Dent';

Sandbox parsing

this.bindNode('sandbox', '.my-node');
this.parseBindings();
ASK A QUESTION

Matreshka#remove(key, eventOptions) matreshka

Deletes a property

Returns matreshka - self

Fires delete delete:KEY

Arguments

Name Type Details
key string

A key or keys which are separated by a space

eventOptions optional eventOptions

An event object

Examples

this.remove('myKey');
this.remove('myKey1 myKey2');

Using eventOptions

this.remove('myKey', {
	silent: true
});
ASK A QUESTION

Matreshka#select(selector) node null

Returns HTML node corresponding to a selector from the sandbox

The method is very similar to Matreshka#selectAll, but it returns only one element or null

Returns node null

Arguments

Name Type Details
selector string

A selector

Examples

this.bindNode('sandbox', '.app');
this.select('.my-element');
// the same as
this.bound().querySelector('.my-element');
// the same as
$('.app').find('.my-element')[0];
ASK A QUESTION

Matreshka#selectAll(selector) $nodes

Returns HTML nodes corresponding to a selector from the sandbox

After sandbox creation by the Matreshka#bindNode method, you can get and use HTML nodes which are located in it. Besides, the method supports the :bound(KEY) selector

Returns $nodes

Arguments

Name Type Details
selector string

A selector

Examples

this.bindNode('sandbox', '.app');
this.selectAll('.my-element');
// the same as
this.$bound().find('.my-element');
// the same as
$('.app').find('.my-element');

The :bound(KEY) selector

this.bindNode('myKey', '.my-element');
this.selectAll(':bound(myKey) .my-another-element');
// the same as
this.$bound('myKey').find('.my-another-element');
// the same as
$('.my-element').find('.my-another-element');
ASK A QUESTION

Matreshka#set(key, value, eventOptions)

Sets a property value allowing to pass an event object as the third argument

The list of the supported flags:

  • silent - do not call the change and change:KEY events
  • silentHTML - do not change states of bound HTML nodes
  • force - call the change and change:KEY events even though the property value has not been changed
  • forceHTML - change a state of bound element even though the property value has not been changed. This option is usable if the bound element has been rendered after the binding (for example, some option tags have been added to select tag)
  • skipMediator - prevents the property transformation by a mediator (see Matreshka#mediate)
  • skipLinks - prevents the work of dependencies created with Matreshka#linkProps

Fires change change:KEY beforechange beforechange:KEY

Arguments

Name Type Details
key string

A key

value *

A value

eventOptions optional eventOptions

An event object

Examples

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.value);
});

// the same as this['myKey'] = 3
// or this.myKey = 3
// alerts 3
this.set('myKey', 3);

Using eventOptions

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.value);
});

// handler isn't called
this.set('myKey', 4, {
	silent: true
});

Passing custom data to a handler

this.on('change:myKey', function(eventOptions) {
	alert(eventOptions.myCustomFlag);
});

// displays 42
this.set('myKey', 4, {
	myCustomFlag: 42
});
ASK A QUESTION

Matreshka#set(keyValuePairs, eventOptions)

Alternative "key-value" syntax of the Matreshka#set method

Arguments

Name Type Details
keyValuePairs object

An object containing key-value pairs

eventOptions optional eventOptions

An event object

Examples

this.set({
	myKey1: 1,
	myKey2: 2
});

Passing eventOptions as second argument

this.set({
	myKey: 3
}, {
	myFlag: 'Jigurda'
});
ASK A QUESTION

Matreshka#setClassFor(key, class, updateCallback)

Available since 1.1.

Sets class for a property

The method allows to precisely determine which class instance the set property will be. A developer doesn't have to worry about the fact that a property value will be accidentally rewritten by wrong type of data.

The method is an addon over Matreshka#mediate and it overrides a mediator excluding the conflict of two mediators.

Class instance is being created during the launch of Matreshka#setClassFor method. The current property value becomes the first argument of the class constructor. Provisions should be made so that either undefined (if a property hasn’t contained any data before), or an object you should do something with (for example, to extend class instance by object properties) will get into the class constructor.

It looks easy in practice: you create an ordinary class which almost always receives some data to be handled (for example, to use them in Matreshka.Object#jset method).

While attempting to assign another value (an object or an array) to the property, the inner mechanism of setClassFor method performs the following instead of assignment:

  • If updateCallback function is given, the method launches it with two arguments: the current property value and the data which code is trying to assign.
  • If given class is inherited from Matreshka.Object, the instance is updated with new data using Matreshka.Object#jset method.
  • If given class is inherited from MMatreshka.Array, the instance is updated with new data using Matreshka.Object#recreate method.
  • If updateCallback function isn’t given and class isn’t inherited from Matreshka.Object or Matreshka.Array, the instance is extended by object properties which code is trying to assign.

A cool feature of this method is the absence of limitations on the class source. Any function-constructor that can be initialized using new operator and not only Matreshka's successors can act as a class.

Arguments

Name Type Details
key string array

Key or an array of keys or a list of keys which are separated by spaces.

class function

Class you want to assign to the property

updateCallback optional function

Function which is called at every attempt of assigning new data to the property, allowing to customize logic of class instance updating with new data. The function receives two arguments: the current property value (class instance) and data which are attempted to assign.

Examples

var SubClass = Class({
	// ...
});

// ...

this.setClassFor('x', SubClass);

// trying to assign another value to property
this.x = {a: 42};

// this.x is still SubClass instance
alert(this.x instanceof SubClass); // true
alert(this.x.a); // 42

The use of updateCallback.

this.setClassFor('x', SubClass, function(instance, data) {
	updateSomeHow(instance, data);
});

Getting parent and key. Besides data (the first argument), two arguments are passed to class constructor: a link to an instance which has called setClassFor and a key of the property.

var MySubClass = Class({
	'extends': Matreshka,
	constructor: function(data, parent, key) {
		// parent - is MyClass instance
		// key equals to "x"
	}
});

var MyClass = Class({
	'extends': Matreshka,
	constructor: function() {
		this.setClassFor('x', MySubClass);
	}
});

A non-standard way of using updateCallback for ignoring any changes of the property.

// MK.noop - is an empty function
this.setClassFor('x', SubClass, MK.noop);

In case if your class doesn’t support the use of new operator, use @link Matreshka#mediate} method instead of setClassFor.

this.mediate('x', function(data, currentValue) {
	return currentValue instanceof SomeClass
		? Object.assign(currentValue, data)
		: SomeLib.initInstance(SomeClass, data);
});

An abstract example with large nested data (for brevity, ECMAScript 7 syntax is used)

// app.js
class App extends MK {
	constructor(appData) {
		this.appData = appData;
		this.setClassFor('appData', AppData);
	}
}

// app-data.js
class AppData extends MK.Object {
	constructor(data) {
		super(data)
			.setClassFor({
				friends: Friends,
				settins: Settings
			});
	}
}

// friend.js
class Friend extends MK.Object {
	constructor(data) {
		super(data);
	}
}

// friends.js
class Friends extends MK.Array {
	Model = Friend;
	trackBy = 'id';
	constructor(data) {
		super(...data);
	}
}

// settings.js
class Settings extends MK.Object {
	constructor(data) {
		super(data)
			.setClassFor('credentials', Credentials);
	}
}

// credentials.js
class Credentials extends MK.Object {
	constructor(data) {
		super(data);
	}
}

// app-init.js
var app = new App({
	settings: {
		name: 'Vasiliy Vasiliev',
		credentials: {
			email: 'vasia.vasia@gmail.com'
		}
	},
	friends: [{
		name: 'Yulia Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}, {
		name: 'nagibator3000',
		id: 3
	}]
});

// data can be serialized and passed to the server
JSON.stringify(app.appData);


// next just to assign new data to appData property
// yet the class structure won’t be changed
app.appData = {
	settings: {
		name: 'Petr Petrov',
		credentials: {
			email: 'petr.petrov@gmail.com'
		}
	},
	friends: [{
		name: 'Yulechka Zuyeva',
		id: 1
	}, {
		name: 'Konstantin Konstantinopolsky',
		id: 2
	}]
};
ASK A QUESTION

Matreshka#setClassFor(keyClassPairs, updateCallback)

Available since 1.1.

Additional syntax for Matreshka#setClassFor, which accepts key-class object as the first argument.

Arguments

Name Type Details
keyClassPairs object

key-class object

updateCallback optional function

Function which is called at every attempt of assigning new data to the property.

Examples

this.setClassFor({
	x: Class1,
	y: Class2,
	z: Class3
}, function(data) {
	instance.jset(data);
});
ASK A QUESTION

Matreshka#trigger(names, arg) matreshka

Fires an event

After adding event handlers using Matreshka#on, Matreshka#onDebounce or Matreshka#once, any event can be fired manually using this method.

Returns matreshka - self

Arguments

Name Type Details
names optional eventNames

An event name or some names which are separated by a space

arg optional *

Any arguments which will be passed to every handler

Links

Examples

this.on('foo bar', function(a, b, c) {
	alert(a + b + c);
});
this.trigger('foo', 1, 2, 3); // alerts 6
ASK A QUESTION

Matreshka#unbindNode(The, node, eventOptions) matreshka

Breaks a binding between given property and HTML node.

Using this method you can delete the binding between a property and HTML node, which has been added recently and no longer needed.

Returns matreshka - self

Fires unbind unbind:KEY

Arguments

Name Type Details
The string null

key or a list of keys which are separated by spaces. If you pass null instead of the key, all bindings for the given instance will be deleted

node optional string node $nodes

HTML node

eventOptions optional eventOptions

Event object ("silent" key disables firing the events "unbind" and "unbind:KEY")

Examples

this.bindNode('myKey', '.my-element');

// changes the property value and the state of the HTML element
this.myKey = true;

this.unbindNode('myKey', '.my-element');

// only the property value is being changed now
this.myKey = false;
ASK A QUESTION

Matreshka#unbindNode(setOfArguments, eventOptions) matreshka

Alternative syntax "heap of arguments" for Matreshka#unbindNode

Returns matreshka - self

Arguments

Name Type Details
setOfArguments array

An array of arrays (see the example)

eventOptions optional eventOptions

(see above)

Links

Examples

var temporaryBindings = [
	[{
		myKey1: '.my-element1'
		myKey2: '.my-element2'
	}],
	[{
		myKey3: '.my-element3'
		myKey4: '.my-element4'
	}, {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... }
	}],
	[{
		myKey5: '.my-element5'
		myKey6: '.my-element6'
	}, {
		on: 'somethingelse',
		getValue: function() { ... },
		setValue: function() { ... }
	}]
];

this.bindNode(temporaryBindings);

// these bindings are no longer needed
this.unbindNode(temporaryBindings);
ASK A QUESTION

Matreshka#$nodes: $nodes

Available since 1.1.

An object contains collections (jQuery, Zepto, bQuery) of bound nodes for quick access.

Links

Examples

this.bindNode('myKey', '.my-node');
this.$nodes.myKey; // the same as $('.my-node')
ASK A QUESTION

Matreshka#nodes: node

Available since 1.1.

The object contains bound elements in the form of separate DOM nodes for quick access.

Pay attention, every object property has got the first node of the bound ones to the corresponding property. Use Matreshka#$nodes for getting all the nodes bound to a certain property.

Links

Examples

this.bindNode('myKey', '.my-node');
this.nodes.myKey; // the same as $('.my-node')[0]
ASK A QUESTION

Matreshka.$bound() $nodes

Available since 1.1.

Returns a collection of bound nodes by given key

This static method works the same as Matreshka#$bound and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns $nodes - Bound nodes

Links

Examples

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.$bound(object, 'x');
ASK A QUESTION

Matreshka.Class()

Available since 0.2.

A link to the Class global function

This way of using the Class function is usable when an application you develop uses AMD

Examples

MK.Class({
	method: function() {}
});

// the same as
Class({
	method: function() {}
});
ASK A QUESTION

Matreshka.bindNode() object

Available since 1.1.

Binds a property of an object to HTML node, implementing two-way data binding

This static method works the same as Matreshka#bindNode and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.bindNode(object, 'x', '.my-node');
ASK A QUESTION

Matreshka.bindOptionalNode() object

Available since 1.1.

Works just the same as Matreshka#bindNode but it does not throw an exception if the node argument is an empty array, undefined or non-existent.

This static method works the same as Matreshka#bindOptionalNode and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.bindOptionalNode(object, 'x', '.my-node');
ASK A QUESTION

Matreshka.bound() node null

Available since 1.1.

Returns the first bound element or null

This static method works the same as Matreshka#bound and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns node null - Bound node

Links

Examples

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.bound(object, 'x');
ASK A QUESTION

Matreshka.boundAll() $nodes

Available since 1.1.

Returns a collection of bound nodes by given key

This static method works the same as Matreshka#boundAll and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns $nodes - Bound nodes

Links

Examples

var object = {},
	bound;
MK.bindNode(object, 'x', '.my-node');
bound = MK.boundAll(object, 'x');
ASK A QUESTION

Matreshka.debounce(f, duration, thisArg)

Available since 0.3.

Calls a function only once after a timer has expired. At every attempt of launching a timer is updated.

This method is an implementation of the debounce micro pattern which solves the problem of multiple call of a function for a certain period of time. See the example and JavaScript Debounce Function.

Arguments

0
Name Type Details
f function

Original function

duration optional number

A delay

thisArg optional *

A context which a function must be launched in

Examples

var debounced = MK.debounce(function( x ) {
	console.log(x);
}, 10);

for(var i = 0; i < 100; i++) {
	debounced(i);
}

// >>> 99
ASK A QUESTION

Matreshka.deepFind(object, path) *

Available since 1.5.

Returns a property from nested object

The function allows to get a property value from nested object. It doesn't throw an error in case if one of objects in given path is not defined.

Returns * - Property value or ``undefined``

Arguments

Name Type Details
object object

An object

path string

A path to a property

Examples

var obj = {
		a: {
			b: {
				c: {
					d: 42
				}
			}
		}
	},
	d = MK.deepFind(obj, 'a.b.c.d');

alert(d); // 42

Bad way

var obj = {},
	d = obj.a.b.c.d; // exception

deepFind returns undefined, if given path is "broken" and doesn't throw an exception

var obj = {},
	d = MK.deepFind(obj, 'a.b.c.d');

alert(d); // undefined
ASK A QUESTION

Matreshka.define() object

Available since 1.1.

Overrides a property descriptor completely using Object.defineProperty

This static method works the same as Matreshka#define and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.define(object, 'myKey', {
	get: function() { ... }
	set: function() { ... }
});
ASK A QUESTION

Matreshka.defineSetter() object

Available since 1.1.

Defines a custom setter for a property

This static method works the same as Matreshka#defineSetter and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.defineSetter(object, 'myKey', function() {
	alert('setter is running');
});
ASK A QUESTION

Matreshka.each(o, callback, thisArg)

Iterates any object running its every property through callback function

This static method is similar to the work of Array.prototype.forEach.

Arguments

Name Type Details
o object

An object

callback function

A function which is launched on every iteration

thisArg optional *

An object which is used as this on calling callback

Examples

var myObject = {
	a: 1,
	b: 2
};
MK.each(myObject, function(value, key) {
	// ...
});
ASK A QUESTION

Matreshka.extend(o1, o2) object

A little additional function which extends one object by means of the other object properties

Returns object - o1

Arguments

Name Type
o1 object
o2 object

Examples

var o1 = {a: 3},
	o2 = {b: 4};

MK.extend(o1, o2);
ASK A QUESTION

Matreshka.get() *

Available since 1.1.

Returns a value of property

This static method works the same as Matreshka#get and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns * - A value

Links

Examples

var object = {},
	val = MK.get(object, 'x');
ASK A QUESTION

Matreshka.linkProps() object

Available since 1.1.

Creates a dependency of one property value on values of others

This static method works the same as Matreshka#linkProps and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.linkProps(object, 'sum', 'a b' function(a, b) {
	return a + b;
});
object.a = 40;
object.b = 2;
alert(object.sum); // 42
ASK A QUESTION

Matreshka.lookForBinder(node) object

Returns a binder corresponding to an element. If it is not found, it returns undefined. The function uses Matreshka.defaultBinders.

Returns object - properties

Arguments

Name Type
node node

Links

Examples

console.log(Matreshka.lookForBinder($('input[type="text"]' )[0]));

// will return the object
{
	on: 'keyup paste',
	getValue: function() { return this.value; },
	setValue: function(v) {
		if( this.value != v ) {
			this.value = v;
		}
	}
}
ASK A QUESTION

Matreshka.mediate() object

Available since 1.1.

Transforms property value on its changing

This static method works the same as Matreshka#mediate and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.mediate(object, 'x', String);
object.x = 42;
alert(typeof object.x); // string
ASK A QUESTION

Matreshka.off() object

Available since 1.1.

Deletes an event handler

This static method works the same as Matreshka#off and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.on(object, 'foo', function(evt) {
	//...
});

MK.off(object, 'foo');
ASK A QUESTION

Matreshka.on() object

Available since 1.1.

Adds an event handler

This static method works the same as Matreshka#on and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.on(object, 'foo', function(evt) {
	alert(evt.hello);
});

MK.trigger(object, 'foo', {hello: 'World'});
ASK A QUESTION

Matreshka.onDebounce() object

Available since 1.1.

Adds an event handler which is called only once during a definite period of time

This static method works the same as Matreshka#onDebounce and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.onDebounce(object, 'foo', function(evt) {
	//...
});
ASK A QUESTION

Matreshka.once() object

Available since 1.1.

Adds event handler which can be called only once

This static method works the same as Matreshka#once and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.once(object, 'foo', function(evt) {
	//...
});
ASK A QUESTION

Matreshka.orderBy(collection, keys, orders=asc) array

Available since 1.6.

Creates an array of elements, sorted by properties of its items

This static method works just like orderBy from lodash. It accepts array-like object as the first arg, a key or a list of keys as the second arg and an order (asc/desc) or a list of orders as the third arg.

Returns array - The new sorted array

Arguments

Name Default Type Details
collection object

A collection (array-like object)

keys string Array.

A key or a list of keys

orders optional asc string Array.

An order or a list of orders corresponding to the list of keys

Examples

A little example taken from lodash documentation

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 42 },
  { 'user': 'barney', 'age': 36 }
];

// sort by `user` in ascending order and by `age` in descending order
MK.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]
ASK A QUESTION

Matreshka.parseBindings() $nodes

Available since 1.1.

Parses DOM tree, declaring bindings with properties enclosed in double braces.

This static method works the same as Matreshka#parseBindings and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns $nodes - Resulting collection of DOM nodes

Links

Examples

var object = {};
var $node = MK.parseBindings(object, '<h3>Hello, {{name}}</h3>');
object.name = 'Arthur Philip Dent';
ASK A QUESTION

Matreshka.randomString() string

The function which returns a unique pseudo-random string.

The new Date().getTime and Math.random() functions are used for generating a string, so returned string is unique.

Returns string - A random string

Examples

var id = MK.randomString();
ASK A QUESTION

Matreshka.select() node null

Available since 1.1.

Returns HTML node corresponding to a selector from a sandbox

This static method works the same as Matreshka#select and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns node null

Links

Examples

var object = {};
MK.bindNode(object, 'sandbox', '.app');
MK.select(object, '.my-element');
ASK A QUESTION

Matreshka.selectAll() $nodes

Available since 1.1.

Returns HTML nodes corresponding to a selector from a sandbox

This static method works the same as Matreshka#selectAll and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns $nodes

Links

Examples

var object = {};
MK.bindNode(object, 'sandbox', '.app');
MK.selectAll(object, '.my-element');
ASK A QUESTION

Matreshka.set() object

Available since 1.1.

Sets a property value allowing to pass an event object as the third argument

This static method works the same as Matreshka#set and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.set(object, 'x', 42, {
	someOption: true
});
ASK A QUESTION

Matreshka.setClassFor() object

Available since 1.1.

Sets class for a property.

This static method works the same as Matreshka#setClassFor and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.setClassFor(object, 'x', SomeClass);
object.x = {a: 42};
alert(this.x instanceof SubClass); // true
alert(this.x.a); // 42
ASK A QUESTION

Matreshka.setProto(proto)

Available since 1.7.

Allows to set custom proto for Matreshka class

Allows to make possible to inherit Matreshka and all its descendants from another class (to be precise, from given prototype). The method requires good understanding of prototype inheritance in JavaScript. The method works everywhere except of IE9 and IE10 because these browsers don't provide nor Object.setPrototypeOf nor __proto__.

Arguments

Name Type Details
proto object

Prototype

Examples

function F() {}

F.prototype.someMethod = function() {
	alert('yep');
};

Matreshka.setProto(F.prototype);
// the same as
// Object.setPrototypeOf(Matreshka.prototype, F.prototype);
// or
// Matreshka.prototype.__proto__ = F.prototype;

var instance = new Matreshka;

alert(instance instanceof F); // true

instance.someMethod(); // 'yep'

You can inherit Matreshka class from anything

// gets all features of React.Component (yep, sounds crazy)
Matreshka.setProto(React.Component.prototype);
ASK A QUESTION

Matreshka.to() matreshka

Available since 1.1.

The function, converting a random structure of objects and arrays into Matreshka.Object and Matreshka.Array instances.

Returns matreshka - a newly created instance of Matreshka

Examples

var mk = MK.to({
	a: 1,
	b: {
		c: 2
	},
	d: [{e: 1}, {e: 2}, {e: 3}]
});
ASK A QUESTION

Matreshka.toArray(arr) array

Available since 1.1.

Converts any array-like object to native array.

The function works twice faster than Array.prototype.slice.

Returns array - New array

Arguments

Name Type Details
arr object array

Any array-like object

Examples

var object = {
	0: 'a',
	1: 'b',
	2: 'c',
	length: 3
};

console.log(MK.toArray(object)); // ['a', 'b', 'c']

Cloning array

var arr = ['a', 'b', 'c'],
	cloneArr = MK.toArray(arr);
ASK A QUESTION

Matreshka.trigger() object

Available since 1.1.

Fires an event

This static method works the same as Matreshka#trigger and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.on(object, 'foo', function(evt) {
	alert(evt.hello);
});

MK.trigger(object, 'foo', {hello: 'World'});
ASK A QUESTION

Matreshka.trim(string) string

Available since 1.1.

Strip whitespace from the beginning and end of a string

The method is usable when you're not sure does browser support String.prototype.trim.

Returns string - A result

Arguments

Name Type Details
string string

A string

Examples

console.log(MK.trim('   hello world  ')); // "hello world"
ASK A QUESTION

Matreshka.unbindNode() object

Available since 1.1.

Breaks a binding between given property and HTML node.

This static method works the same as Matreshka#unbindNode and all its variations, but accepts any kind of JavaScript objects as first argument.

Returns object - The first argument

Links

Examples

var object = {};
MK.unbindNode(object, 'x', '.my-node');
ASK A QUESTION

Matreshka.useAs$($)

Available since 0.2.

Forces to use a definite DOM-library

By default, Matreshka uses a library which can be found by window.$ reference. If there is no such a variable in the global namespace or it does not include a necessary set of methods, the built-in micro-library bQuery is used.

The Matreshka.useAs$ method makes Matreshka use a library you would like to use in spite of its absence in the global namespace or for a different reason (for example, if two different versions of jQuery are used on a page). It is desirable to launch the method before your code starts.

Arguments

Name Type Details
$ function

Any library (jQuery, Zepto, bQuery or others)

Examples

Matreshka.useAs$(jQuery.noConflict());
ASK A QUESTION

Matreshka.defaultBinders: array

An array of functions which return a corresponding binder

Matreshka.defaultBinders - The array of functions which check an element in turn against given rules in these functions and return a binder (see binder). This method is used when the third argument has not been passed to the Matreshka#bindNode method. See more detailed information about bindings in Matreshka#bindNode documentation.

Links

Examples

A custom checkbox

// add the binder to the collection of binders
MK.binders.customCheckbox = function() {
	return {
		on: 'click',
		getValue: function() {
			return $(this).hasClass('checked');
		},
		setValue: function( v ) {
			$(this).toggleClass('checked', !!v);
		},
		initialize: function() {
			$(this).toggleClass('checked');
		}
	}
};

// unshift method adds a function to the beginning of the Matreshka.defaultBinders array
MK.defaultBinders.unshift( function( element ) {
	// check if the element has the "custom-checkbox" class name
	if($(element).hasClass('custom-checkbox')) {
		// if checking is OK, return a new binder
		return MK.binders.customCheckbox();
	}
});

// ...

this.bindNode('myKey', '.custom-checkbox');
ASK A QUESTION

Matreshka.parserBrackets: object

Available since 1.5.

Contains brackets for bindings parser

parserBrackets object allows to change default syntax of the parser. It contains two properties: left (left bracket, "{{" by default) and right (right bracket, "}}" by default)

Examples

Use syntax [[=property]] instead of {{property}}

MK.parserBrackets.left = '[[=';
MK.parserBrackets.right = ']]';
ASK A QUESTION

Matreshka.binders object

The namespace for binders. This object can be extended by you so as not to make a mess of the global namespace.

Take a little agreement into consideration: every property from the Matreshka.binders collection must be made as a function which returns a binder.

Links

Examples

MK.binders.myCoolBinder = function(var1, var2) {
	return {
		on: 'click',
		getValue: function() { ... },
		setValue: function() { ... },
		initialize: function() { ... }
	};
};

this.bindNode('myKey', '.my-element',
	MK.binders.myCoolBinder('Hello', 'World'));
ASK A QUESTION

Matreshka.binders.html() binder

Available since 0.1.

Returns data binder which changes innerHTML of bound DOM node depending on instance property value.

Returns binder

Examples

this.bindNode('myKey', '.my-element', MK.binders.html());
ASK A QUESTION

Matreshka.binders.display(value=true) binder

Available since 0.1.

Returns data binder which controls a visibility of DOM node (using style.display) depending on the instance property value

Returns binder

Arguments

Name Default Type Details
value optional true boolean

If the argument equals true, the node is hidden when a property value is falsy; if it equals false, it is hidden when the property value is truly.

Examples

this.bindNode('myKey', '.my-element', MK.binders.display(true));
this.bindNode('myKey', '.my-element', MK.binders.display(false));
ASK A QUESTION

Matreshka.binders.className(className) binder

Available since 0.1.

Returns data binder which switches over DOM node class name depending on instance property value. If property value equals true non-strictly, a class name is added, otherwise - it's removed. The logic can be changed by adding a bang character in front of a class name and in this way, a class name will be added when a property value equals false non-strictly and vice versa.

Returns binder

Arguments

Name Type
className string

Examples

this.bindNode('myKey', '.my-element', MK.binders.className('foo'));

this.myKey = true; // adds the 'foo' class

this.myKey = false; // removes the 'foo' class

The use of the bang character in front of a class name

this.bindNode('myKey', '.my-element', MK.binders.className('!foo'));

this.myKey = false; // adds the 'foo' class

this.myKey = true; // removes the 'foo' class
ASK A QUESTION

Matreshka.binders.prop(property) binder

Available since 0.3.

Returns data binder which changes given property of DOM node depending on instance property value.

Returns binder

Arguments

Name Type
property string

Examples

this.bindNode('disabled', '.my-button', MK.binders.prop('disabled'));

// sets disabled = true property for the node
this.disabled = true;

// sets disabled = false property for the node
this.disabled = false;
ASK A QUESTION

Matreshka.binders.attr(attribute) binder

Available since 0.3.

Returns data binder which changes an attribute of DOM node depending on instance property value

Returns binder

Arguments

Name Type
attribute string

Examples

this.bindNode('image', 'img.my-image', MK.binders.attr('src'));

this.image = 'http://example.com/cats.jpg';
ASK A QUESTION

Matreshka.binders.input(type) binder

Available since 0.3.

Returns data binder which binds instance property to an input value. It is not obligatory to use the binder directly because it is included in the Matreshka.defaultBinders list.

Returns binder

Arguments

Name Type Details
type optional string

Input type

Examples

this.bindNode('myKey', '.my-input', MK.binders.input('range'));
ASK A QUESTION

Matreshka.binders.output() binder

Available since 0.3.

Returns data binder which binds instance property to an output value. It is not obligatory to use the binder directly because it is included in the Matreshka.defaultBinders list.

Returns binder

Examples

this.bindNode('myKey', '.my-input', MK.binders.output());
ASK A QUESTION

Matreshka.binders.textarea() binder

Available since 0.3.

Returns data binder which binds instance property to a textarea value. It is not obligatory to use the binder directly because it is included in the Matreshka.defaultBinders list.

Returns binder

Examples

this.bindNode('myKey', '.my-textarea', MK.binders.textarea());
ASK A QUESTION

Matreshka.binders.select(multiple) binder

Available since 0.3.

Returns data binder which binds instance property to a select value. It is not obligatory to use the binder directly because it is included in the Matreshka.defaultBinders list.

Returns binder

Arguments

false
Name Type Details
multiple optional boolean

If select is multiple

Examples

this.bindNode('myKey', '.my-select', MK.binders.select(true));
ASK A QUESTION

Matreshka.binders.progress() binder

Available since 1.1.

Returns data binder which binds instance property to a progress value. It is not obligatory to use the binder directly because it is included in the Matreshka.defaultBinders list.

Returns binder

Examples

this.bindNode('myKey', '.my-progres', MK.binders.progress());
ASK A QUESTION

Matreshka.binders.text() binder

Available since 1.1.

Returns data binder which changes textContent of bound DOM node depending on instance property value.

Returns binder

Examples

this.bindNode('myKey', '.my-progres', MK.binders.text());
ASK A QUESTION

Matreshka.binders.style(property) binder

Available since 1.1.

Returns data binder which changes given style property of bound DOM node depending on instance property value.

Returns binder

Arguments

Name Type Details
property string

A property of style object (camel-cased)

Examples

this.bindNode('myKey', '.my-progres', MK.binders.style('backgroundColor'));
this.myKey = 'red'; // background-color of .my-progress is red now
ASK A QUESTION

Matreshka.binders.dataset(property) binder

Available since 1.1.

Returns data binder which changes given dataset property of bound DOM node depending on instance property value.

Returns binder

Arguments

Name Type Details
property string

A property of dataset object

Examples

this.bindNode('myKey', '.my-progres', MK.binders.dataset('myProp'));
this.myKey = 'cool value';
ASK A QUESTION

Matreshka.binders.file(readAs) binder

Available since 1.1.

Returns binder for input[type="file"].

Binder allows not only to get basic data about a file, but also to read it without calling FileReader manually.

If readAs argument isn’t set, input value gets into the bound property after its changing (on "change" DOM event). If readAs is set, binder will read the file and transform it into the needed format (data URI, Blob...) and only after reading the file, the property will be changed.

The file (native File) or an array of files becomes the final value of the property in the presence of multiple attribute. At the same time the result of reading will get into the object of every file as readerResult property.

Returns binder

Arguments

Name Type Details
readAs optional string

readAs argument value can be "arrayBufer", "binaryString", "dataURL", "text". The value depends on the presence of corresponding methods of the FileReader prototype

Links

Examples

this.bindNode('myKey', '.my-file', MK.binders.file('dataURL'));
// ... user changes input content
// choosing my-image.png from file system ...
this.on('change:myKey', function() {
	console.log(this.myKey);
	// -->
	// File
	//	lastModified: 1383404384000
	//	lastModifiedDate: ...
	//	name: "my-image.png"
	//	readerResult: "data:image/png;base64,iVBO..."
	//		- the result of file reading
	//	size: 9378
	//	type: "image/png"
});
ASK A QUESTION

Matreshka.binders.dropFiles(readAs) binder

Available since 1.8.

Returns binder which allows to drop files from a file manager to given block.

After Matreshka#bindNode is called the HTML block gets needed DOM event listeners (eg, dragover and drop). When user drops files from the file manager into the block, the property gets an array of dropped files as its value. As like Matreshka.binders.file the binder accepts one optional argument called readAs which says how the files need to be read by FileReader: data URI, Blob... (the result of reading is placed in readerResult property of every file). If readAs isn't given, the property gets an array of files which wasn't read.

Returns binder

Arguments

Name Type Details
readAs optional string

readAs argument value can be "arrayBufer", "binaryString", "dataURL", "text". The value depends on the presence of corresponding methods of the FileReader prototype

Links

Examples

this.bindNode('myKey', '.drop-area', MK.binders.dropFiles('dataURL'));
// ... user drops one file called
// "my-image.png" into .drop-area block
this.on('change:myKey', function() {
	console.log(this.myKey[0]);
	// -->
	// File
	//	lastModified: 1383404384000
	//	lastModifiedDate: ...
	//	name: "my-image.png"
	//	readerResult: "data:image/png;base64,iVBO..."
	//		- the result of file reading
	//	size: 9378
	//	type: "image/png"
});
ASK A QUESTION

Matreshka.binders.dragOver() binder

Available since 1.9.

Makes given property equal to true when something is dragged over given node.

Returns binder

Examples

this.bindNode('myKey', '.my-node', MK.binders.dragOver());
this.on('change:myKey', function() {
	if(this.myKey) {
		console.log('something is dragging over .my-node');
	} else {
		console.log('nothing is dragged over the node');
	}
});

Add dragovered class name when file (or another draggable object) is dragged over .my-node

this.bindNode('myKey', '.my-node', MK.binders.dragOver());
this.bindNode('myKey', '.my-node', MK.binders.className('dragovered'));
ASK A QUESTION

Class Matreshka.Object

Matreshka.Object is a class which is responsible for key-value data. Its goal is to separate service properties from data that can be passed to a server or kept in a local storage. The class is inherited from the Matreshka class and includes all its properties and methods.

Imagine you create a class including "a", "b" and "c" properties. Let's assume that "a" and "b" are the properties which must be sent to a server, and "c" property is just responsible for some application state (for example, it contains the sum of "a" and "b"). The server does not need the "c" property. So we have to separate the properties which are responsible for data from ones which are not.

In order to declare such properties from others, you can make use of the Matreshka.Object#addDataKeys method.

this.addDataKeys('a b');

this.a = 1;
this.b = 2;
this.c = 3;

If you don't know which properties are specified in advance, you can always use the Matreshka.Object#jset method, which declares not only properties responsible for data but sets their values at once.

this.jset({
    a: 1,
    b: 2
});

this.c = 3;

After an application has found out what is data, Matreshka.Object instance can be converted into an ordinary object by the Matreshka.Object#toJSON method and passed to a server or kept in a local DB (for example, in localStorage).

// will return the object {a: 1, b: 2}
this.toJSON();

The modify event is fired on changing properties which are responsible for data

this.on('modify', function() {
    alert('Object is modified');
});

Arguments

Name Type Details
data optional object Data
collection optional matreshkaArray An array, where this object is added as Model

Examples

Simple use.

new MK.Object();

Creation of an instance with two specified properties.

// the same as new MK.Object().jset({a: 1, b: 2});
new MK.Object({a: 1, b: 2});

The inheritance.

var MyClass = Class({
	'extends': MK.Object,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

The inheritance using ECMAScript 2015 syntax

class MyClass extends MK.Object {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Data enumerating, using for..of syntax from ECMAScript 2015

var mkObject = new MK.Object({a: 1, b: 2});
for(let item of mkObject) {
	console.log(item); // 1 .. 2
}
ASK A QUESTION

Matreshka.Object#addDataKeys(keys) matreshkaObject

Adds keys to a list of keys which are responsible for data.

This method is used when you need to declare keys which are responsible for data but values of corresponding properties are not known yet.

Returns matreshkaObject - self

Arguments

Name Type Details
keys string array

A key or keys which are separated by spaces or an array of keys

Examples

this.addDataKeys('a b');
this.addDataKeys(['a', 'b']);
this.addDataKeys('a', 'b');

Using Matreshka.Object#each method

this.addDataKeys('a b');

this.each( function(value, key) {
	console.log(key, value);
});
// displays  'a' undefined and 'b' undefined
ASK A QUESTION

Matreshka.Object#each(callback, thisArg) matreshkaObject

Iterates properties which are responsible for data through callback function.

This method is very similar to Array.prototype.forEach.

Returns matreshkaObject - self

Arguments

Name Type Details
callback function

A function which is called on every iteration

thisArg optional *

A context of a function

Examples

this.each(function(value, key) {
	...
}, this );
this
	.jset({a: 1, b: 2})
	.addDataKeys('c')
	.each(function(value, key) {
		console.log(key, value);
	}, this);
;
// >>> a 1, b 2, c undefined
ASK A QUESTION

Matreshka.Object#hasOwnProperty(key) matreshkaObject

Checks if there is a property which is responsible for data with given key in an instance.

Returns matreshkaObject - self

Arguments

Name Type
key string

Examples

var mkObject = new MK.Object({
	a: 1,
	b: 2
});

mkObject.hasOwnProperty('a'); // true

mkObject.hasOwnProperty('b'); // true

mkObject.hasOwnProperty('c'); // false
ASK A QUESTION

Matreshka.Object#jset(key, value, evtOpts) matreshkaObject

Sets a property and adds a key to a list of keys which are responsible for data.

This method does two things:

1. Sets a specified value to a given property.

2. Adds a key to data keys list which it makes property available for using in the Matreshka.Object#each, Matreshka.Object#keys, Matreshka.Object#toObject and Matreshka.Object#toJSON methods).

Apart from that, the method works the same as Matreshka#set.

Returns matreshkaObject - self

Fires change change:KEY modify

Arguments

Name Type Details
key string

A key

value *

A value

evtOpts optional eventOptions

An event object

Links

Examples

this.jset('a', 1).jset('b', 2);
this.jset('a', 1).jset('b', 2);

// assign 3 to the 'c' property,
// but do not add the key to a list of keys which are responsible for data
this.set('c', 3);

this.each(function(value, key) {
	console.log(key, value);
});

// displays  'a' 1 and 'b' 2

console.log(this.keys()); // displays  ['a', 'b']

console.log(this.toJSON()); // displays  {a: 1, b: 2}

After using the Matreshka.Object#jset method, you can work with a property like with an ordinary one

this.jset('a', 1).jset('b', 2);
this.set('a', 3);
this.b = 4;
ASK A QUESTION

Matreshka.Object#jset(keyValuePairs, evtOpts) matreshkaObject

Alternative syntax of the Matreshka.Object#jset method that uses a "key-value" object for setting several properties at once

Returns matreshkaObject - self

Arguments

Name Type Details
keyValuePairs object

A key-value object

evtOpts eventOptions

A event object

Examples

this.jset({
	a: 1,
	b: 2
});

The usage of event object

this.jset({
	a: 1,
	b: 2
}, {silent: true});
ASK A QUESTION

Matreshka.Object#keyOf(value) string null

Searches for specified property value among others which are responsible for data and returns a key if this value has been found (very similar to Array.prototype.indexOf function)

Returns string null

Arguments

Name Type Details
value *

A value of any type which should be found among data keys

Examples

var mkObject = new MK.Object({
	a: 1,
	b: 2
});

mkObject.keyOf(1); // 'a'

mkObject.keyOf(2); // 'b'

mkObject.keyOf(3); // null
ASK A QUESTION

Matreshka.Object#remove(key, evtOptions) matreshkaObject

Deletes a property from a Matreshka.Object class instance and from a list of keys which are responsible for data.

Returns matreshkaObject - self

Fires delete delete:KEY modify

Arguments

Name Type Details
key string

A key (or a list of keys which are separated by spaces)

evtOptions optional eventOptions

An event object

Links

Examples

this.remove('myKey');
this.remove('myKey1 myKey2');

The usage of an event object

this.remove('myKey', {silent: true});
ASK A QUESTION

Matreshka.Object#removeDataKeys(keys) matreshkaObject

Deletes keys from a list of keys which are responsible for data (but does not delete given properties)

Returns matreshkaObject - self

Arguments

Name Type Details
keys string array

A key or keys which are separated by spaces or an array of keys

Examples

this.removeDataKeys('a b');
this.removeDataKeys(['a', 'b']);
this.removeDataKeys('a', 'b');
ASK A QUESTION

Matreshka.Object#toJSON() object

Converts an instance and Matreshka.Object internal properties into an ordinary object.

Returns object

Examples

var mkObject = new MK.Object({
	a: 1,
	b: 2,
	c: new MK.Object({
		d: 3,
		e: 4
	})
});

// returns  {a: 1, b: 2, c: {d: 3, e: 4}}
mkObject.toJSON();
ASK A QUESTION

Class Matreshka.Array

The Matreshka.Array serves as collection class in Matreshka framework. It is inherited from the Matreshka class, obtaining all parent possibilities without exception. Besides, Matreshka.Array has all methods that ordinary array has.

All the methods which have been adopted from the built-in Array work like their originals.

A programmer familiar to the methods of native Array can understand immediately by means of which method adds (push, unshift, splice), deletes (pop, shift, splice), sorts (sort, reverse) items etc. An exception from this rule is the forEach method which in its original form always returns undefined and in case with Matreshka.Array it returns itself for the chained call possibility. For the reason that methods work exactly the same as original ones, they are not presented in this documentation separately but they are gathered in the Matreshka.Array#METHOD section.

this.push(1, 2, 3);
this.pop();

All methods adopted from built-in Array which modify an array can be called with an event object passing.

The method_ syntax is used for this, where underscore at the end of a method name means that the last argument is an event object. Such methods are not given in this documentation because it is necessary to remember their syntax only. See Matreshka.Array#METHOD_.

this.push_(1, 2, 3, {
    silent: true
});
this.pop_({
    silent: true
});

A developer has an opportunity of catching any data modification.

While using a methods adopted from built-in Array, events with corresponding name are fired. Calling the push method, the push event is fired, calling the pull method, the pull event is fired, calling the sort method, the sort event is fired, and so on... The list of arguments can be obtained addressing the args property.

this.on('push', function(evt) {
    console.log(evt.args); // [1,2,3]
});

this.push(1, 2, 3);

While adding items, the add and addone events are fired. The first one is fired once on adding (for example, you have added few items using push and the event has been called only once), the second one is fired once on every added item. On the add event triggering, an array of added items is passed to an event object (added property) and on the addone triggering, each particular added item is passed to it.

this.on('add', function(evt) {
    console.log(evt.added); // [1,2,3]
});

this.push(1, 2, 3);
// the handler will be launched three times,
// as three new item have been added to the array
this.on('addone', function(evt) {
    console.log(evt.added); // 1 ... 2 ... 3
});

this.push(1, 2, 3);

On removing items the same logic is observed: remove triggers once even though several items have been removed and the removeone event triggers for each removed item individually. Removed items are contained in the removed property of an event object.

this.push(1, 2, 3, 4, 5);

this.on('remove', function(evt) {
    console.log(evt.removed); // [2,3,4]
});

this.splice(1, 3);
this.push(1, 2, 3, 4, 5);

// the handler will be launched three times,
// as three items have been removed from the array
this.on('removeone', function(evt) {
    console.log(evt.removed); // 2 ... 3 ... 4
});

this.splice(1, 3);

On every modification of an array the modify event is fired, allowing to catch all changes in the array (adding, removing, re-sorting) without any exception.

this.on('modify', function(evt) {
    ...
});

length is an ordinary property which can be bound to HTML node or you can catch changes using the change:length event.

For example, on adding three items using the push method with three arguments, the following events: push, add, addone (three times), modify, change:length are fired..

Model

The Matreshka.Array#Model property specifies a model class of items that an array contains. Its behavior is very similar to model property from Backbone.Collection. It is recommended to inherit Model from the Matreshka.Object class or the Matreshka.Array one (in case if it is necessary to get a collection of collections) in order to get the opportunity of converting an array into an ordinary one by using the Matreshka.Array#toJSON method.

// define Model
var MyModel = Class({
    // it is inherited from MK.Object
    'extends': MK.Object,
    constructor: function(data) {
        // set passed properties by jset method
        this.jset(data);
    }
});

// define the class for a collection
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
});

// create class instance
var myArray = new MyArray();

// add two items
myArray.push({
    a: 1,
    b: 2
}, {
    a: 3,
    b: 4
})

// will return [{a: 1, b: 2}, {a: 3, b: 4}]
myArray.toJSON();

Automatic rendering

Matreshka.Array can render HTML nodes on a page automatically in any modifications of an array. The Matreshka.Array#itemRenderer property is used for that. You do not have to worry about rebuilding the HTML tree, Matreshka.Array does it for you. The example of the usage of automatic list rendering is below.

<ul class="my-list"></ul>
var MyModel = MK.Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);

        // wait for the 'render' event
        this.on('render', function() {
            // and bind the 'value' property
            // to the newly created <li> HTML node
            this.bindNode('value', ':sandbox', MK.binders.html());
        });
    }
});

var MyArray = MK.Class({
    'extends': MK.Array,
    Model: MyModel,
    // define the renderer for each item of the collection
    itemRenderer: '<li>',
    constructor: function() {
        // create a sandbox
        this.bindNode('sandbox', '.my-list');
    }
});

var myArray = new MyArray();
myArray.push({
    value: 'Hello'
}, {
    value: 'World'
});

For more detailed information read the documentation of Matreshka.Array#itemRenderer.

Links

Examples

An instance creation

new MK.Array();

An instance creation with length specifying

new MK.Array(42);

Items passing on creation

new MK.Array('Hi', {a: 'b'});

The inheritance

var MyClass = Class({
	'extends': MK.Array,
	constructor: function() {
		this.sayHello();
	},
	sayHello: function() {
		alert("Hello World!");
	}
});

The inheritance using ECMAScript 2015 syntax

class MyClass extends MK.Array {
	constructor() {
		this.sayHello();
	}
	sayHello() {
		alert("Hello World!");
	}
}

Data enumerating, using the for..of syntax from ECMAScript 2015

var mkArray = new MK.Array(1, 2, 3);
for(let item of mkArray) {
	console.log(item); // 1 .. 2 .. 3
}

Listening to events

this.on('modify', function( evt ) {
	alert('1) the ' + evt.method + ' method has been called');
});

this.on('shift', function(evt) {
	alert('2) the ' + evt.method + ' method has been called');
});

this.push(1); // 1) the push method has been called

this.shift(); // 1) the shift method has been called, 2) the shift method has been called

An event object passing to native-like Array method

this.on('modify', function(evt) {
	alert(evt.customData);
});

this.push_(1, {
	silent: true // event is not fired
});

this.shift_({
	customData: 42 // alerts 42
});
ASK A QUESTION

Matreshka.Array#METHOD()

Any method from Array.prototype

Matreshka.Array includes all the methods existing in the native JavaScript Array:

Yet they work the same as the Array.prototype. There are only a few remarks:

  • The forEach method returns an array itself instead of undefined
  • The methods which return a new array (splice, slice, filter, map...) originally, in Matreshka they return a new Matreshka.Array instance.

Moreover, the methods generate the events which are fired on any array modification. For more detailed information look at Matreshka.Array.

Links

Examples

this.push(1, 2, 3);
var mapped = this
	.forEach(function(value, index) {
		//...
	})
	.map(function(value, index) {
		//...
	})
;
alert(mapped.isMKArray);
this.reverse();
ASK A QUESTION

Matreshka.Array#METHOD_()

Any method from Array.prototype with the possibility of passing event object.

Having found out more about Matreshka.Array#METHOD, it becomes clear that the methods do not support an event object passing as they exactly duplicate the syntax and the number of arguments of the built-in Array. The METHOD_ syntax allows to pass some data to event handlers.

The list of available flags:

  • silent: true - disables event triggering
  • dontRender: true - disables rendering
  • skipMediator: true - disables mediators and models

Links

Examples

this.push_(1, 2, 3, {
    silent: true
});

this.pop_({
    silent: true
});
this.on('modify', function(evt) {
	alert(evt.flag); // 42
});

this.push_(1, 2, 3, {
	flag: 42
});
ASK A QUESTION

<virtual>Matreshka.Array#Model(data, mkArray, index)

Available since 0.2.

The property defines a class of items which will be inserted to a collection

Every time items are added to an array, the built-in handler checks if added item is Model instance and converts it into the one if the check fails. This behavior is very similar to the model property from Backbone.Collection. It is recommended to inherit Model from the Matreshka.Object or Matreshka.Array class (in case if it is necessary to get a collection of collections) to get an opportunity of an array conversion into ordinary one by means of the Matreshka.Array#toJSON method.

Use Matreshka.Array#mediateItem for more flexible control of an item class (for example, if you need to use one Model for certain items and another one - for others).

Arguments

Name Type Details
data object

Data which have been passed to a constructor

mkArray matreshkaArray

An array where an item has been added to

index number

Current index of an instance in the parent array

Links

Examples

// define Model
var MyModel = Class({
	// it is inherited from MK.Object
	'extends': MK.Object,
	constructor: function(data, parentArray, index) {
		// set passed properties by jset method
		this.jset(data);
		this.doSomething();
	},
	doSomething: function() { ... }
});

// define collection class
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
});

// create an instance
var myArray = new MyArray();

// add two items
myArray.push({
    a: 1,
    b: 2
}, {
    a: 3,
    b: 4
})

//  will return [{a: 1, b: 2}, {a: 3, b: 4}]
myArray.toJSON();

Model and the ECMAScript 2015

class MyArray extends MK.Array {
	get Model() {
		return MyModel;
	}
}

Model and the ECMAScript 7

class MyArray extends MK.Array {
	Model = MyModel;
	constructor() { ... }
}
ASK A QUESTION

Matreshka.Array#each(callback, thisArg) matreshkaArray

Works the same as the forEach method which enumerates array items

Returns matreshkaArray - self

Arguments

Name Type Details
callback function

A function which is called on every iteration

thisArg optional *

An object which is used as this on calling callback

Examples

this.each(function(item, index) {
	console.log(index, item);
});
ASK A QUESTION

Matreshka.Array#hasOwnProperty() boolean

Returns true if a property is present in an instance (index or length property)

Returns boolean

Examples

var mkArray = new MK.Array(42); // creates the array of the length 42

mkArray.hasOwnProperty(5); // true

mkArray.hasOwnProperty(100500); // false

mkArray.hasOwnProperty('length'); // true

mkArray.hasOwnProperty('blah'); // false
ASK A QUESTION

Matreshka.Array#mediateItem()

Available since 0.1.

Transforms an item value while inserting.

This method is used to define the typing for the inserted items. Note that calling of this method overrides the Matreshka.Array#Model property.

Links

Examples

// all the array items are numbers
this.mediateItem(Number);
this.push(1, 2, 3, 4, 5);

// all the array items are strings
this.mediateItem(function(value) {
	return String(value);
});

this.push(6, 7);

this.unshift(true, {});

// ["true", "[object Object]", "1", "2", "3", "4", "5", "6", "7"]
console.log( mkArray.toJSON() );

The "conditional Model"

this.mediateItem(function(item) {
	if(item.something) {
		return new FirstModel(item);
	} else {
		return new SecondModel(item);
	}
});
ASK A QUESTION

<virtual>Matreshka.Array#onItemRender(item, renderEvt)

Available since 1.1.

A function which is launched before "render" event.

To improve the readability of code and to get a little speed gain, in 1.1 version onItemRender virtual method has presented which can be used as a substitute for "render" event.

At the same time onRender method is called in a rendered element with the only argument - an event object.

Arguments

Name Type Details
item matreshka

A rendered node of a collection

renderEvt matreshka

"render" event object

Examples

var MyModel = Class({
	'extends': MK.Object,
	constructor: function(data) {
		this.jset(data);
	},
	onRender: function(renderEvt) {
		this.bindNode('isChecked', ':sandbox .my-checkbox');
		this.bindNode('text', ':sandbox .text', MK.binders.html());
	}
});

var MyArray = Class({
	'extends': MK.Array,
	Model: MyModel,
	itemRenderer: '<li>',
	constructor: function() {
		this.bindNode('sandbox', '.my-form');
	},
	onItemRender: function(item, renderEvt) {
		// also do something
	}
});

var app = new MyArray();
ASK A QUESTION

Matreshka.Array#orderBy(keys, orders=asc) matreshkaArray

Available since 1.6.

Sorts by properties of the items

The method uses Matreshka.sortBy for ordering and it's sorting this instead of creation of new array.

Returns matreshkaArray - self

Arguments

Name Default Type Details
keys string Array.

A key or a list of keys

orders optional asc string Array.

An order or a list of orders corresponding to the list of keys

Examples

A little example taken from lodash documentation

this.recreate([
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 42 },
  { 'user': 'barney', 'age': 36 }
]);

// sort by `user` in ascending order and by `age` in descending order
this.orderBy(['user', 'age'], ['asc', 'desc']);
// → [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":42}]
ASK A QUESTION

Matreshka.Array#pull(index, evtOptions) * null

Available since 0.1.

Removes an item with specified index from an array and returns this item.

Returns * null - A deletee or ``null``

Fires pull remove removeone modify

Arguments

Name Type Details
index string number *

An item index (a number or a string) which has to be removed or the deletee itself (which is neither a number nor a string)

evtOptions optional eventOptions

An event object in case if it is necessary to pass some data to event handlers or to set the silent flag which prevents events triggering.

Examples

Passing of an index

var removed;

this.recreate(['a', 'b', 'c']);

removed = this.pull(1);

alert(removed); // 'b'

alert(this.toString()); // 'a,c'

Passing of a deletee object

var object1 = {},
	object2 = {},
	object3 = {},
	removed;

this.push(object1, object2, object3);

removed = this.pull(object2);

alert(removed === object2); // true

alert(this.length); // 2
ASK A QUESTION

Matreshka.Array#recreate(array, eventOptions) matreshkaArray

Recreates the Matreshka.Array instance.

The method allows to convert any array (or an object which has "length" property) into the Matreshka.Array instance. If nothing has been passed as the first argument, the instance is cleansed.

Returns matreshkaArray - self

Fires recreate modify add addone remove removeone

Arguments

Name Type Details
array optional array

An array or array-like object

eventOptions optional eventOptions

An event object

Links

Examples

// cleanse the array and add 5 new items
this.recreate([1, 2, 3, 4, 5]);

// cleanse the array
this.recreate();
ASK A QUESTION

Matreshka.Array#rerender(options) matreshkaArray

Available since 0.3.

Rerenders DOM nodes of items which are included into an instance.

This method renders array items in an array container. If a node which is associated to an array item has already been created, the method reinserts it into the container or sandbox of the array instead of rerendering it all over again.

The method can be useful in case when items have been added to the array before declaring a sandbox or a container.

Starting with the 1.1 version, in order to make an array rerender itself regardless of the presence of the rendered nodes (for example, you use handlebars in itemRenderer), pass an object with forceRerender property which equals true to the method.

Returns matreshkaArray - self

Arguments

Name Type Details
options optional object

An object with flags (there is an only forceRerender flag for the time being)

Examples

this.rerender({
	forceRerender: true
});
ASK A QUESTION

Matreshka.Array#restore(selector, eventOptions) matreshkaArray

Available since 1.3.

Restores Matreshka.Array instance from existing HTML nodes on a page.

In case if a collection is pre-rendered on the page (eg via webserver), the method can restore collection from existing HTML nodes.

<!-- One, Two, Three are prerendered -->
<ul class="collection-node">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <script type="text/html" class="renderer">
        <li></li>
    </script>
</ul>
var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.addDataKeys('value');
        this.set(data);
    },
    onRender: function() {
        this.bindNode('value', ':sandbox', MK.binders.html())
    }
});

var MyCollection = Class({
    'extends': MK.Array,
    itemRenderer: ':sandbox .renderer',
    constructor: function() {
        this
            .bindNode('sandbox', '.collection-node')
            .restore(':sandbox li');
    }
});

var myCollection = new MyCollection();
myCollection.push({
    value: 'Four'
});

console.log(myCollection.toJSON());
// [{value: 'One'}, {value: 'Two'}, {value: 'Three'}, {value: 'Four'}]

If selector arg isn't passed then the collection will be restored from child nodes that placed in a container ("container" or "sandbox").

The method fires "render" event and calls onRender and onItemRender functions (look at the docs) for every newly added item (similar to usual rendering).

Returns matreshkaArray - self

Fires recreate modify add addone

Arguments

Name Type Details
selector optional selector

A selector

eventOptions optional eventOptions

Event object

Examples

this.restore();
ASK A QUESTION

<virtual>Matreshka.Array#itemRenderer: string function

Available since 0.1.

HTML string, selector or function which is responsible for rendering DOM nodes of an array on a page.

The itemRenderer overridable property which allows to render corresponded HTML nodes of items of an array without a programmer's participation. On a new item insertion into an array, HTML node is created automatically. This node becomes a sandbox (see. Matreshka#bindNode) for inserted item and it is inserted into HTML container which is defined in an array.

Where is created node inserted?

In order to define HTML container where rendered HTML nodes will be inserted, it is necessary to define a container. HTML sandbox should be declared for an array or a special container key should be bound to the HTML container for that. Read more detailed information about bindings and sandboxes in Matreshka#bindNode. Sandbox usage as a container:

<ul class="my-list"></ul>
var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li>',
    Model: MyModel,
    constructor: function() {
        // define a sandbox
        this.bindNode('sandbox', '.my-list');
    }
});

Now all newly created <li> nodes will get into the .my-list node.

If you do not want to insert HTML nodes straight into the sandbox, you can bind container property to needed HTML node. This logic is required in case if a sandbox is not limited by collection items alone and it includes other HTML nodes.

<div class="my-widget">
    <h1>This is my awesome list</h1>
    <ul class="my-list"></ul>
</div>
var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li>',
    Model: MyModel,
    constructor: function() {
        // define a sandbox
        this.bindNode('sandbox', '.my-widget');
        // define a container for HTML nodes
        this.bindNode('container', '.my-list');
    }
});

In the example above the HTML nodes will be inserted into .my-list instead of .my-widget.

The itemRenderer property supports a few variants of defining, but they all must contain or return the only HTML node.

HTML string as property value

As you can see from the example above itemRenderer can be defined as an HTML string.

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<div class="my-div">Be cool</div>',
    constructor: function() { ... }
});

A selector as property value

In case if you carry over the templates for the items to the HTML page, itemRenderer supports the selector as value. When this occurs, Matreshka.Array will search for HTML node in DOM tree and it will extract innerHTML of found node. In case if a node is not found, the exception will be thrown.

HTML string is different from a selector due to the presence of the < symbol in a string.

<script type="text/html" id="be-cool-template">
    <div class="my-div">Be cool</div>
</script>
var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel
    itemRenderer: '#be-cool-template',
    constructor: function() { ... }
});

A function as property value

The usage of a function as the itemRenderer property value gives an additional code flexibility if it is necessary to dynamically generate HTML node for rendering. A function can return:

HTML string

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: function() {
        return '<div class="my-div">Be cool</div>';
    },
    constructor: function() { ... }
});

A selector

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: function() {
        return '#be-cool-template';
    },
    constructor: function() { ... }
});

DOM node

var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: function() {
        return document.createElement('div');
    }
});

Parent renderer overriding by the render property

Sometimes it is convenient to declare a renderer inside a model class as Backbone does. The renderer property overrides the itemRenderer value if it is specified for a child item of a collection.

var MyModel = Class({
    'extends': MK.Object,
    renderer: '<div class="my-div">Be cool</div>',
    constructor: function( data ) { ... }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<frameset>Not cool</frameset>',
    constructor: function() { ... }
});

In this case you do not have to designate itemRenderer at all because render of a child item adopts all its roles. The syntax remains the same: HTML string, a selector or a function can be used.

The render event

After an item has been inserted into an array and its HTML node has already been created but it hasn't been inserted into the container yet, the render event is fired on inserted item. After its triggering you can declare needed data bindings.

<form class="my-form"></form>
var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);

        // wait for the event triggering
        this.on('render', function() {
            this.bindNode('isChecked', ':sandbox .my-checkbox');
            this.bindNode('text', ':sandbox .text',
                MK.binders.html());
        });
    }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '<label>\
        <input type="checkbox" class="my-checkbox">\
        <span class="text"></span>\
    </label>',
    constructor: function() {
        this.bindNode('sandbox', '.my-form');
        this.push({
            isChecked: true,
            text: 'Be cool'
        }, {
            isChecked: false,
            text: 'Produce shitcode'
        });
    }
});

var app = new MyArray();

The code above will create the following HTML tree:

<form class="my-form">
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Be cool</span>
    </label>
    <label>
        <input type="checkbox" class="my-checkbox">
        <span class="text">Produce shitcode</span>
    </label>
</form>

And it will bind the checkboxes to the corresponding isChecked and text properties. The live example

Remember, the opportunity of catching the delegated events is implemented in Matreshka. The array can catch an event of an item rendering itself, using the *@render event name (see the documentation of eventNames).

this.on('*@render', function(evt) {
    alert('Child item is rendered');
});

Rendered HTML node becomes a sandbox for inserted item allowing to use the :sandbox selector and some other possibilities after rendering. If an item enters a few collections at once, set the bindRenderedAsSandbox: false property to it so as to cancel this behavior.

var MyModel = Class({
    'extends': MK.Object,
    bindRenderedAsSandbox: false
    // ...
});

The afterrender event

After render event is fired Matreshka starts zero timer setTimeout(f, 0) which calls afterrender event. In this way you can get actual information about node position and another data which is available only when DOM node inserted to the document.

var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        //...
        this.on('afterrender', function() {
            console.log('Computed style', getComputedStyle(this.sandbox));
        });
        //...
    }
});
// ...

onItemRender and onRender

To improve the readability of the code and a small gain in performance, version 1.1 presents the new virtual method called Matreshka.Array#onItemRender, which can be used instead of render event. As second alternative, the onRender can be used for a model.

var MyModel = Class({
    'extends': MK.Object,
    constructor: function(data) {
        this.jset(data);
    },
    onRender: function(evt) {
        this.bindNode('isChecked', ':sandbox .my-checkbox');
        this.bindNode('text', ':sandbox .text',
                MK.binders.html());
    }
});

var MyArray = Class({
    'extends': MK.Array,
    Model: MyModel,
    itemRenderer: '...`,
    constructor: function() {
        //...
    },
    onItemRender: function(item, evt) {
        //...
    }
});

var app = new MyArray();

The template engine

If you have a look at the examples of using Matreshka.Array and Matreshka.Array#itemRenderer, you can notice that all logic which is responsible for the two-way and one-way data binding is contained in JavaScript code. It is one of the main Matreshka advantages. But when you develop a very simple collection which does not include complicated logic, lots of bindings, etc, you would like to have a shorter variant of the binding declaration. The template including bindings can be passed to itemRenderer for that. Starting version 1.1 the template engine is turned on by default.

var MyArray = Class({
    'extends': MK.Array,
    Model: MK.Object,
    itemRenderer: '<label>\
        <input type="checkbox" checked="{{isChecked}}">{{text}}\
    </label>',
    constructor: function() {
        this.bindNode('sandbox', '.my-form');
        this.push({
            isChecked: true,
            text: 'Be cool'
        }, {
            isChecked: false,
            text: 'Produce shitcode'
        });
    }
});

var app = new MyArray();

The example above is completely the same as the previous one, but it does not require to create a separate class for the Model as we do not have to catch the render event and to declare bindings manually. Live example

Pay attention: The code speed is lower with the template engine than without it. It happens because of complex logic that implements it. If you want to turn it off you need: assign false to the Matreshka.Array#useBindingsParser or just don't use {{KEY}} syntax (the engine works only when a node or HTML string includes double braces).

The template engine is powered by Matreshka#parseBindings.

The cancellation of rendering.

As is seen from above if the render property of the child item is specified, Matreshka.Array will try to render it. In order to completely cancel rendering for an array, assign renderIfPossible: false.

var MyArray = Class({
    'extends': MK.Array,
    renderIfPossible: false,
    // ...
});

Moving object across few collections

By default, when you add an object to an array the Matreshka will try to render it using itemRenderer (if it's not rendered yet). It gives a great advantage in cases when you have two or more lists which include the same object. The lists react instantly on any change in the object.

But sometimes you just need to move an object across few collections without re-rendering it again. If you need to move object to another collection including its sandbox use the moveSandbox flag.

this.push_(item, {
    moveSandbox: true
})

Reassigning the itemRenderer

Starting version 1.1, when you reassign itemRenderer a collection rerenders automatically.

this.itemRenderer = '<div class="new-renderer"></div>';

This ability allows to load renderer from server.

// jQuery.get example
jQuery.get('templates/template.html', function(data) {
    this.itemRenderer = data;
}.bind(this));

// Fetch API example
fetch('templates/template.html')
    .then(function(resp) {
        return resp.text();
    })
    .then(function(data) {
        this.itemRenderer = data;
    }.bind(this));

// Fetch API + ECMAScript 2015 example
fetch('templates/template.html')
    .then(resp => resp.text())
    .then(data => this.itemRenderer = data);

To render the only objects which aren't yet rendered use Matreshka#set with forceRerender: false flag.

this.set('itemRenderer', renderer, {forceRerender: false});

It's useful when you use server prerendering (look at the Matreshka.Array#restore) and template needs to be loaded asynchronously.

var MyArray = Class({
    'extends': MK.Array,
    constructor:  function() {
        this
            .bindNode('sandbox', '.some-node')
            .restore();

        jQuery.get('templates/template.html', function(data) {
            this.set('itemRenderer', data, {forceRerender: false})
        }.bind(this));
    }
});

Rendering of a collection that contains any kind of object

In the version 1.1, the biggest innovation is native objects support in methods like Matreshka.bindNode, Matreshka.linkProps, Matreshka.mediate and so on. This great opportunity did not spare the collection rendering. That means you no longer need to think about Matreshka.Array#Model value because array renderer supports any kind of object (including native ones).

var MyArray = Class({
    'extends': MK.Array,
    // Model is not defined
    itemRenderer: ...
    constructor: function() { ... }
    onItemRender: function(item) {
        MK.bindNode(item, 'x', ':sandbox .some-node');
    }
})

To make sure that passed items are objects (not null or number etc) you can use native Object constructor as a model

var MyArray = Class({
    'extends': MK.Array,
    Model: Object,
    itemRenderer: ...,
    constructor: function() { ... }
})

One more little example: the rendering of simple list:

var MyArray = Class({
    'extends': MK.Array,
    itemRenderer: '<li></li>',
    constructor: function() {
        this.bindNode('sandbox', '.my-list');
    }
});

var arr = new MyArray();
arr.push({value: 'Item 1'}, {value: 'Item 2'});

Links

Examples

ECMAScript 2015

class MyArray extends MK.Array {
	get itemRenderer() {
		return '<div>';
	},
	constructor() { ... }
}

ECMAScript 7

class MyArray extends MK.Array {
	itemRenderer = '<div>';
	constructor() { ... }
}
ASK A QUESTION

<virtual>Matreshka.Array#trackBy: string

Available since 1.2.

trackBy property indicates a key of unique IDs for collection items.

In case if a client and a server activelly communicate with each other and collection items have unique IDs, then redrawing entire collection from scratch does not make sense. After the server respond with new collection, much better to check does the old collection contain objects which have the corresponding identifiers. If object ID from new collection matches object ID from old one, old object will be updated and used again. That means a new object (new instance of Matreshka.Array#Model) will not be created and new DOM node will not be rendered.

trackBy says which property of collection item is an identifier. Using trackBy you can get great performance enhancement in cases when you render really huge collections.

trackBy works only using Matreshka.Array#recreate because recreate is the only method which recreates collection from scratch.

In examples below _id key is used as identifier (you can use any other key).

var MyArray = Class({
    'extends': MK.Array,
    trackBy: '_id'
    constructor: function() {
        //,,,
    }
});

var arr = new MyArray();

// adds 3 objects to the collection
arr.recreate([
    {_id: 0, name: 'Foo'},
    {_id: 1, name: 'Bar'},
    {_id: 2, name: 'Baz'}
]);

// the next recreate call
// removes an object with _id: 0
// adds an object with _id: 3
// updates an object with _id: 3 (changes name from Bar to BarNew)
// updates an object with _id: 2 (changes name from Baz to BazNew)
// resorts collection
arr.recreate([
    {_id: 1, name: 'BarNew'},
    {_id: 3, name: 'Qux'},
    {_id: 2, name: 'BazNew'}
]);

trackBy can have "$index" value, allowing to update objects by their index in collection.

var MyArray = Class({
    'extends': MK.Array,
    trackBy: '$index'
    constructor: function() {
        //,,,
    }
});

var arr = new MyArray();

// adds 3 objects to the collection
arr.recreate([
    {name: 'Foo'},
    {name: 'Bar'},
    {name: 'Baz'}
]);

// the next recreate call
// updates all 3 items with new "name"
// adds an object with name "Qux"
arr.recreate([
    {name: 'NewFoo'},
    {name: 'NewBar'},
    {name: 'NewBaz'},
    {name: 'Qux'}
]);

Links

ASK A QUESTION

Matreshka.Array.from(arrayLike, mapFn, thisArg) matreshkaArray

Available since 1.1.

The function creates a new Matreshka.Array instance from array-like object.

Returns matreshkaArray

Arguments

Name Type Details
arrayLike object

Array-like object.

mapFn optional function

The mapping function which is called for each element of an array.

thisArg optional *

An object which is used as this on calling mapFn

Links

Examples

var mkArray = MK.Array.from([1, 2, 3, 4]);
var mkArray = MK.Array.from([1, 2, 3, 4], function(item) {
	return item*2;
}, this);
ASK A QUESTION

Matreshka.Array.of() matreshkaArray

Available since 1.1.

The function creates a new Matreshka.Array instance with a variable number of arguments, regardless of number or type of the arguments.

Returns matreshkaArray

Links

Examples

var mkArray = MK.Array.of(1, 2, 3, 4);
ASK A QUESTION

Class(prototype, statics) class

A class implementation based on the prototype inheritance

The Class function allows to use the classic OOP based on classes.

Returns class - class (a class constructor to be exact)

Arguments

Name Type Details
prototype object Methods and properties
statics optional object Static methods and properties

Examples

var A = Class({
	method1: function() { ... }
});

var B = Class({
	// B is inherited from A
	'extends': A,
	method2: function() { ... }
});

var C = Class({
	// С is inherited from B
	'extends': B,
	method2: function() {
		// calling the parent method
		B.prototype.method2.apply(this, arguments);
	},
	method3: function(a, b) { ... }
});

var D = Class({
	// D is inherited from C
	'extends': C,
	method3: function(a, b) {
		// calling the parent method
		C.prototype.method2.call(this, arguments);
	}
});

Passing an object with static methods and properties

var MyClass = Class({
	method: function() { ... }
}, {
	staticProp: 'foo',
	staticMethod: function() {
		return 'bar';
	}
});

alert(MyClass.staticProp); // foo
alert(MyClass.staticMethod()); // bar

The usage of AMD (named modules)

require.config({
	paths: {
		'xclass': 'path/to/matreshka.min',
		'matreshka': 'path/to/matreshka.min',
		'bquery': 'path/to/matreshka.min'
	}
});
require(['xclass', 'matreshka', 'bquery'], function(Class, MK, $) {
	var MyClass = Class({
		'extends': MK,
		constructor: function() {
			// ...
		}
	});
});

The usage of AMD (unnamed module)

// Matreshka contains the Class and $b functions as static properties
require(['path/to/matreshka.min'], function(MK) {
	var MyClass = MK.Class({
		'extends': MK,
		constructor: function() {
			// ...
		}
	});
});

The usage of the Class function is not required. Matreshka OOB supports any type of prototype inheritance including ECMAScript 2015 syntax.

class A extends B {
	constructor() {
		super();
		this.sayHello();
	}

	sayHello() {
		alert("Hello World!");
	}
}
ASK A QUESTION

$b()

Available since 0.1.

bQuery micro-library

bQuery (previously called Balalaika) is a tiny jQuery-like library for working with DOM. It is inherited from Array.prototype and includes all the methods existing in native Array:

Besides, it includes several own methods: on, off, is, extend, HTML parsing feature, DOM-ready feature and others. bQuery is used by the internal organs of Matreshka only when jQuery or another jQuery-like library is not enabled on a page.

Examples

Adding DOM event listener

$('.my-selector').on('click.namespace', function() {
    alert('hi');
});

Removing DOM event listener

$('.my-selector').off('click.namespace');

The is method

$('.my-selector').on('click', function(evt) {
    if($(evt.target).is('.another-selector')) {
        alert('hi');
    }
});

The extend method (extension of one object by another one)

var myObject = {a: 1};
$.extend(myObject,{
    b: 2
});

DOM-ready

$(function() {
    // Do something with DOM
});

Parsing

var elements = $('<div><span class="yeah"></span></div>');

Searching for one element in another one

var myElement = $('.my-selector', node);

Setting styles

$('.my-selector').forEach(function(el) {
    $.extend( el.style, {
        width: '30px',
        backgroundColor: 'red'
    });
});

The event delegation

$('.my-selector').on('click', function(evt) {
    var node = evt.target;
    while(node !== this) {
        if($(node).is('.delegated-selector')) {
            // Handle it!
            break;
        }
        node = node.parentNode;
    }
});

A simple plugin

$.fn.addClass = function(className) {
    this.forEach(function(item ) {
        var classList = item.classList;
        classList.add.apply(classList, className.split(/\s+/));
    });
    return this;
};

The create function is an additional utility for creating elements which comes standard with Matreshka. The first argument is a tag name, the second one - properties which extend DOM object.

var div = $.create('div', {
	className: 'my-div',
	innerHTML: 'My DIV',
	dataset: {
		a: 1,
		b: 2
	}
});

starting with version 1.1, function create has alternative syntax. A tag name can be passed as tagName property and list of children as children property.

var div = $.create({
	tagName: 'div',
	className: 'my-div',
	innerHTML: 'My DIV',
	children: [{
		tagName: 'span',
		className: 'div-child',
		innerHTML: 'first child'
	}, {
		tagName: 'span',
		className: 'div-child',
		innerHTML: 'second child'
	}]
});
ASK A QUESTION

eventHandler: function

Event handler. Takes any arguments passed to Matreshka#trigger

Arguments

Name Type Details
options * Any arguments

Examples

var eventHandler = function() {
	console.log(arguments);
}
this.on('fyeah', eventHandler);
this.trigger('fyeah', 'foo', 'bar', 'baz'); // logs 'foo', 'bar', 'baz'

bQuery: array

bQuery collection

eventNames: string

Event name or space-delimited list of event names.

This is very brief description of event names. The full article about events you can find at this article.

Custom events.
this.on('myevent', function() {...});
this.trigger('myevent');
change:KEY which is triggered every time when a property is changed.
this.on('change:x', function(evt) {...});
this.x = 42;
beforechange:KEY which is triggered every time before a property is changed.
this.on('beforechange:x', function(evt) {...});
this.x = 42;
bind:KEY and bind which are triggered after data binding.
//for any property
this.on('bind', function(evt) {...});
//for "x" property
this.on('bind:x', function(evt) {...});
this.bindNode('x', '.my-node');
delete:KEY and delete which are triggered after property removal.
//for any property
this.on('delete', function(evt) {...});
//for "x" property
this.on('delete:x', function(evt) {...});
this.remove('x');
addevent:NAME and addevent which are triggered on event initialization.
//for any event
this.on('addevent', function(evt) {...});
//for "someevent" event
this.on('addevent:someevent', function(evt) {...});
//the line below fires "addevent" and "addevent:someevent"
this.on('someevent', function(evt) {...});
DOM_EVENT::KEY, where DOM_EVENT is a name of DOM event, KEY is a key. A handler is called when DOM_EVENT is triggered on a node bound to the KEY.
this.bindNode('x', '.my-div');
this.on('click::x', function(evt) {
    alert('clicked ".my-div"');
});
DOM_EVENT::KEY(SELECTOR), where DOM_EVENT is a name of DOM event, KEY is a key, SELECTOR is a selector. A handler is called when DOM_EVENT is triggered on a node which matches the SELECTOR within a node bound to the KEY.
<div class="my-div">
    <button class="my-button"></button>
</div>
this.bindNode('x', '.my-div');
this.on('click::x(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});
DOM_EVENT::(SELECTOR), where DOM_EVENT is a name of DOM event, SELECTOR is a selector. A handler is called when DOM_EVENT is triggered on a node which matches the SELECTOR within a sandbox.
this.bindNode('sandbox', '.my-div');
this.on('click::(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});

The same as:

this.bindNode('sandbox', '.my-div');
this.on('click::sandbox(.my-button)', function(evt) {
    alert('clicked ".my-button"');
});
Delegated events: PATH@EVENT, where PATH is a path to a target object whose events we want to listen, EVENT is an event name.
this.on('a@someevent', function() {...});
this.on('a.b.c@change:d', function() {...});

If you need to listen an event of every item of Matreshka.Array or every data key of Matreshka.Object, you can use an asterisk "*" instead of specific key.

this.on('*@someevent', function() {...});
this.on('*.b.*.d@change:e', function() {...});
Any combinations. All events described above can be combined.
this.on('x.y.z@click::(.my-selector)', function() {...});

binder: object

binder contains all information about how to synchronize instance property value with DOM node state. Every member of a binder uses HTML node as context (this)

Properties

Name Type Details
on optional string function DOM event (or space-delimited list of events) which tells when node state is changed. Besides, it accepts function as value if you need to catch change arbitrarily
getValue optional function A function which tells how to retrieve value (state) from HTML node when DOM event is fired
setValue optional function A function which tells how to change DOM node when property value is changed
initialize optional function A function which calls before binding is launched. For example it can initialize some jQuery plugin

Examples

var binder = {
	on: 'click',
	getValue: function(options) {
		return this.value;
	}
	setValue: function(v, options) {
		this.value = v;
	},
	initialize: function(options) {
		alert('Binder is initialized. Initial input value=' + this.value);
	}
};

this.bindNode( 'a', '.my-checkbox', binder );
var binder = {
	on: function(callback) {
		this.onclick = callback;
	},
	getValue: function(options) {
		return this.value;
	}
	setValue: function(v, options) {
		this.value = v;
	},
	initialize: function(options) {
		alert('Binder is initialized. Initial input value=' + this.value);
	}
};

this.bindNode( 'a', '.my-checkbox', binder );

eventOptions: object

An object which can contain service flags or custom data which will be passed to an event handler

Examples

var eventOptions = {silent: true};

this.a = 1;

this.on('change:a', function() {
	alert('a is changed');
});

this.set('a', 2, eventOptions); // no alert
var eventOptions = {f: 'yeah'};

this.a = 1;

this.on('change:a', function(eventOptions) {
	alert(eventOptions.f);
});

this.set('a', 2, eventOptions); // alerts "yeah"

class: function

A class (more precisely constructor of a class) returned by Class function

Examples

var MyClass = Class({
	method: function() { ... }
});

node

DOM node

$nodes

DOM nodes collection. For example, jQuery-node(s)

string

String

boolean

Boolean

number

Number

object

Object

array

Array

function

Function

null

null

*

Any type

MatreshkaMagic

Some developers don’t need Matreshka’s abundant functionality, but they want to use the superb utilities which are present in the framework. That’s why, we have decided to create a new compact library which is called MatreshkaMagic. The library doesn’t include classes (Matreshka, Matreshka.Object, Matreshka.Array and Class function), but it contains all static methods and properties of Matreshka class:

The library is in the folder /magic/ of the repo at github. Having added the script via script tag, MatreshkaMagic global var and its brief variant magic are available for the programmer. Var is an ordinary object with methods.

<script src="magic/matreshka-magic.min.js"></script>
var object = {};
magic.bindNode(object, 'x', '.my-node');
magic.linkProps(object, 'y', 'x z', function(x, z) {
    return x + z;
});
magic.mediate(object, 'z', Number);
// and etc

While using AMD or CJS, global vars aren’t being created:

require(['magic/matreshka-magic.min'], function(magic) {
    //...
});
var magic = require('magic/matreshka-magic.min');

As of writing this documentation, matreshka-magic.min.js file is a bit less than 30KB in the uncompressed form contrary to 46KB of matreshka.min.js. If it’s necessary to include all the framework to your project at some stage, you should just change paths to the script file and change the var names from magic or MatreshkaMagic to MK or Matreshka (it's only obligatory in case if you don’t use AMD or CJS in the project).

FAQ

Is there a wrapper over XMLHttpRequest (AJAX) in Matreshka?

Nope. Firstly, there are a lot of wonderful libraries implementing communications with a server, such as a one-time hot jQuery.ajax, a terrific library qwest, based on Promises and many others.

Secondly, all browsers will probably get a native Fetch API support as an alternative to XMLHttpRequest. fetch has got a simpler and cleaner API, based on Promises and allowing to avoid a catastrophic number of callbacks as well as the necessity of remembering about API XMLHttpRequest. As fetch isn’t supported by all browsers yet, you can use a popular polyfill.

Promises and asynchronous functions from ECMAScript 7 specification give an opportunity to write JavaScript code of surpassing beauty:

async function getData() {
    let resp = await fetch(someUrl);
    let data = await resp.text();

    console.log(data);
}

getData();

Is there a routing in Matreshka?

Yep and nope. Similar to AJAX, there are lots of wonderful libraries implementing routing in the Internet, for example director. But for simple tasks and tasks of average complexity (99% of all projecs) you can use a plugin which implements two-way data binding between URL and object properties. The plugin fits perfectly into the concept of Matreshka, adding to an app the easiest way of URL control ever.

How does Matreshka work?

Matreshka uses accessors, setters in particular, for implementing the two-way data binding and catching the events of property changing. One of the main setter peculiarities is the lightning speed which can be compared to the speed of working with ordinary properties. In their performance accessors are ahead of other solutions such as Object.observe and, especially, dirty-checking.

As an example of how the two-way data binding works (bindNode function in particular), have a look at this code:

window.bindNode = function bindNode(object, key, node, binder) {
    var value = object[key];
    Object.defineProperty(object, key, {
        get: function() {
            return value;
        },
        set: function(v) {
            binder.setValue.call(node, v);
        }
    });

    node.addEventListener(binder.on, function() {
        value = binder.getValue.call(node);
    });
};

As you see, it’s real easy (for simplicity, the function doesn’t support many-to-many binding). You can see the example of function working at jsbin..

Does Matreshka support the server rendering?

Unfortunately, not yet (for the time being). Matreshka uses DOM templating which requires the presence of the library, implementing DOM API on the server. jsdom is a good example of such a library. The problem is that a lot of clients connect to the server and each of them can request completely different pages which are generated dynamically. DOM templating works quite slower than HTML one, where an ordinary text is a template instead of numerous DOM objects.

The server rendering of React components which also require DOM template engine can be mentioned as an example. As a rule, this task is solved with the help of gimmicks and recommendations to use the template caching (which is not always possible, but if it’s possible it can cause memory leaks). Even using the best practices and smart solutions, an ordinary text HTML template engine (let’s say, mustache.js) will solve the problem a lot faster, and the speed on the server is known to be more important than the one on the client.

That’s why, currently, the only recommendation for the server rendering is passing the task of HTML line generation to any text template engine. Let’s leave highly tailored tasks to be performed by the tools which do it best.

Supported browsers

Firefox Chrome Opera Internet Explorer Safari iOS Safari Opera Mini Android Browser Yandex Browser
<8 <14 <11.6 <9 * <5 <4 <11 <2.2 <14
8+ 14+ 11.6+ 9+ 5+ 4+ 11+ 2.2+ 14+
  • All tests are passed.
  • Unknown. Matreshka have not been tested in these browsers.
  • Some tests aren't passed.

Note that:

  • File reading feature for Matreshka.binders.file isn't included to the table. It depends on browser support of FileReader API. To find out is FileReader supported by specific browser, please look at Caniuse page.
  • Setting Matreshka proto via Matreshka.setProto isn't included to the table. It depends on browser support of Object.setPrototypeOf or __proto__.

Can't find your browser? Open browser test yourself.

Found inaccuracy or typo?
Select it and press
+
Ошибка на сайте