# Matreshka.js ```html ``` ## Why Matreshka For pages whose HTML already exists: server-rendered apps, widgets, old code, a single HTML file. Add one ` ``` This site serves the same file: [/matreshka.min.js](https://matreshka.js.org/matreshka.min.js). ### An ES module from a CDN Without a bundler, `matreshka.min.mjs` is the same code as one ES module: every named export of `matreshka`, with `initRouter`, `Router` and `parseForm` included. It's one request, as small as the script-tag file. ```html ``` ## Modules Every static function or class is a named export of the main module. ```js import { MatreshkaArray, bindNode, binders } from 'matreshka'; const { prop } = binders; ``` ## Importance levels The API is split up 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. Start with [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode), [`Matreshka#calc`](https://matreshka.js.org/#Matreshka-calc), [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on), [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) and [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array). ### The second level: recommended to learn If you already know the quick-start basics, you can look at less important (but still important) methods and properties of the framework. ### The third level: other methods and properties We've hidden rarely used parts (Matreshka.js API is really rich). If you want to know everything about Matreshka.js, choose on the switch in the menu. **Warning**. If you open a link to a method or a property of the third level of importance, the third level is turned on automatically. Next: [Hello World and other examples](https://matreshka.js.org/#examples). --- # Website instructions ## Importance levels The API is split up 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 less important (but still important) methods and properties of the framework. ### The third level - other methods and properties We've hidden rarely used parts (Matreshka.js API is really rich). If you want to know everything about Matreshka.js, choose on the switch in the menu. **Warning**. If you open a link to a method or a property of the third level of importance, the third level is turned on automatically. ## Inaccuracies and typos In a footer of every article of the documentation you can find a link to a source of that article. You can fix a typo directly at Github editor. > The documentation is written using GitHub Flavored Markdown. ## Modules The framework is one package with three entry points. ```js import Matreshka from 'matreshka'; import { initRouter } from 'matreshka/router'; import { parseForm } from 'matreshka/parse-form'; ``` --- # Examples ## Hello World Writing your first application is very easy. You should: **1\.** Create an HTML file with the following content ```html My first Matreshka.js application
``` **2\.** Create the application class at **js/app.js** ```js // store html binder in a short variable const htmlBinder = Matreshka.binders.html; // create the class which inherits Matreshka class Application extends Matreshka { constructor() { super(); // bind a 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', htmlBinder()); // if the property "x" has changed, // inform about it in the console this.on('change:x', () => console.log(`x is changed to "${this.x}"`)); } } const app = new Application(); ``` **3\.** That's it! Now you can open the developer's console (by pressing F12) and write: ```js app.x = 'Hello World!'; ``` Cool, isn't it? You can work with such magical properties directly. [Run it live](https://matreshka.js.org/examples/hello-world/). ### Links - [`Matreshka` class](https://matreshka.js.org/#Matreshka) - [`Matreshka#bindNode` method](https://matreshka.js.org/#Matreshka-bindNode) - [`Matreshka#on` method](https://matreshka.js.org/#Matreshka-on) ## Live examples Each example runs on this site; its source code is in the [examples folder](https://github.com/finom/matreshka/tree/main/examples) of the repository. 1. [TodoMVC](https://matreshka.js.org/examples/todomvc/) – a to-do list. ([Source code with annotations](https://matreshka.js.org/examples/todomvc/docs/todomvc/js/app.html), [source](https://github.com/finom/matreshka/tree/main/examples/todomvc)) 2. [TreeView](https://matreshka.js.org/examples/treeview/) of unlimited nesting depth. ([Source](https://github.com/finom/matreshka/tree/main/examples/treeview)) 3. [Markdown editor](https://matreshka.js.org/examples/markdown-editor/) made with few lines of code. ([Source](https://github.com/finom/matreshka/tree/main/examples/markdown-editor)) 4. [Contact List](https://matreshka.js.org/examples/contact-list/) – allows to add, remove, sort, search and change contacts. ([Source](https://github.com/finom/matreshka/tree/main/examples/contact-list)) 5. [A login form](https://matreshka.js.org/examples/matreshka-object/) made with `Matreshka.Object`. ([Tutorial](https://github.com/finom/matreshka/tree/main/examples/matreshka-object)) 6. [A table of users](https://matreshka.js.org/examples/matreshka-array/) made with `Matreshka.Array`. ([Tutorial](https://github.com/finom/matreshka/tree/main/examples/matreshka-array)) 7. [matreshka/router demo](https://matreshka.js.org/examples/router/#!/foo/bar/baz/) – properties bound to parts of the URL. ([Source](https://github.com/finom/matreshka/tree/main/examples/router)) 8. [matreshka/parse-form demo](https://matreshka.js.org/examples/parse-form/) – form fields bound to properties by their names. ([Source](https://github.com/finom/matreshka/tree/main/examples/parse-form)) 9. [Signup form](https://matreshka.js.org/examples/signup-form/) – a server-rendered form: the email is checked as you type, a bar shows the password's strength. ([Source](https://github.com/finom/matreshka/tree/main/examples/signup-form)) 10. [Product table](https://matreshka.js.org/examples/product-table/) – search, sorting and a filter over rows rendered by `Matreshka.Array`. ([Source](https://github.com/finom/matreshka/tree/main/examples/product-table)) 11. [Price widget](https://matreshka.js.org/examples/price-widget/) – a widget on someone else's page, kept inside its own root by `bindSandbox`. ([Source](https://github.com/finom/matreshka/tree/main/examples/price-widget)) ## Tutorials - [The events](https://github.com/finom/matreshka/tree/main/examples/events) – an article about the event engine, which powers `calc`, `bindNode`, `instantiate` and the rest. - [`Matreshka.Object`](https://github.com/finom/matreshka/tree/main/examples/matreshka-object) and [`Matreshka.Array`](https://github.com/finom/matreshka/tree/main/examples/matreshka-array) step by step, with the live examples above. --- # Matreshka **Class** **Import:** ```js import Matreshka from 'matreshka'; ``` The class ``Matreshka`` is a core of the Matreshka.js framework which is inherited by [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array), [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) (and every class of an application you create). It contains the main functionality of the framework: [mediators](https://matreshka.js.org/#Matreshka-mediate), [dependencies](https://matreshka.js.org/#Matreshka-calc), [two-way data binding](https://matreshka.js.org/#Matreshka-bindNode), [an event engine](https://matreshka.js.org/#Matreshka-on), etc. This class usually isn't used directly. Instead, it is inherited by other classes. ## Links - [`Matreshka.Class`](https://matreshka.js.org/#Matreshka.Class) ## Examples **Creating of an instance** ```js const matreshka = new Matreshka(); ``` **Inheritance** ```js class MyClass extends Matreshka { constructor() { super().sayHello(); } sayHello() { alert("Hello World!"); } } ``` **Inheritance using [`Matreshka.Class`](https://matreshka.js.org/#Matreshka.Class)** ```js const MyClass = Matreshka.Class({ 'extends': Matreshka, constructor() { this.sayHello(); }, sayHello() { alert("Hello World!"); } }); ``` ## Methods and properties - [`bindNode`](https://matreshka.js.org/#Matreshka-bindNode) – Binds a property of an object to HTML node, implementing two-way data binding - [`bindOptionalNode`](https://matreshka.js.org/#Matreshka-bindOptionalNode) – Works just the same as [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) but it does not throw an exception if the ``node`` argument is an empty array, ``undefined`` or non-existent. - [`bindSandbox`](https://matreshka.js.org/#Matreshka-bindSandbox) – Binds a sandbox - [`calc`](https://matreshka.js.org/#Matreshka-calc) – Creates a dependency of one property value on values of others - [`instantiate`](https://matreshka.js.org/#Matreshka-instantiate) – Creates fixed class instance - [`isMatreshka`](https://matreshka.js.org/#Matreshka-isMatreshka) – ``isMatreshka`` always equals ``true`` for instances of [`Matreshka`](https://matreshka.js.org/#Matreshka) - [`mediate`](https://matreshka.js.org/#Matreshka-mediate) – Transforms property value on its changing - [`$nodes`](https://matreshka.js.org/#Matreshka-$nodes) – An object contains arrays of bound nodes for quick access. - [`nodes`](https://matreshka.js.org/#Matreshka-nodes) – The object contains bound elements in the form of separate DOM nodes for quick access - [`off`](https://matreshka.js.org/#Matreshka-off) – Deletes an event handler - [`on`](https://matreshka.js.org/#Matreshka-on) – Adds an event handler - [`onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) – Adds an event handler which is called only once during a definite period of time - [`once`](https://matreshka.js.org/#Matreshka-once) – Adds an event handler which can be called only once - [`parseBindings`](https://matreshka.js.org/#Matreshka-parseBindings) – Parses DOM tree, declaring property bindings on which are double braced. - [`remove`](https://matreshka.js.org/#Matreshka-remove) – Deletes a property - [`select`](https://matreshka.js.org/#Matreshka-select) – Returns HTML node corresponding to a selector from a sandbox - [`selectAll`](https://matreshka.js.org/#Matreshka-selectAll) – Returns HTML nodes corresponding to a selector from a sandbox - [`set`](https://matreshka.js.org/#Matreshka-set) – Sets a property value allowing to pass event options object as the third argument - [`trigger`](https://matreshka.js.org/#Matreshka-trigger) – Fires an event - [`unbindNode`](https://matreshka.js.org/#Matreshka-unbindNode) – Destroys a binding between given property and HTML node ## Static methods - [`Class`](https://matreshka.js.org/#Matreshka.Class) – An implementation of classes based on the prototype inheritance - [`bindNode`](https://matreshka.js.org/#Matreshka.bindNode) – Binds a property of an object to HTML node, implementing two-way data binding - [`bindOptionalNode`](https://matreshka.js.org/#Matreshka.bindOptionalNode) – Initializes two-way data binding but does not throws an exception if ``node`` argument is an empty array, ``undefined`` or non-existent - [`bindSandbox`](https://matreshka.js.org/#Matreshka.bindSandbox) – Binds or re-binds sandbox node - [`calc`](https://matreshka.js.org/#Matreshka.calc) – Creates a dependency of one property value on values of others - [`chain`](https://matreshka.js.org/#Matreshka.chain) – Allows chained calls of universal methods - [`defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) – An array of functions which return a corresponding binder - [`instantiate`](https://matreshka.js.org/#Matreshka.instantiate) – Creates fixed class instance - [`initRouter`](https://matreshka.js.org/#Matreshka.initRouter) – Turns on two-way data binding between properties and parts of the URL - [`lookForBinder`](https://matreshka.js.org/#Matreshka.lookForBinder) - [`mediate`](https://matreshka.js.org/#Matreshka.mediate) – Transforms property value on its changing - [`off`](https://matreshka.js.org/#Matreshka.off) – Deletes an event handler - [`on`](https://matreshka.js.org/#Matreshka.on) – Adds an event handler - [`onDebounce`](https://matreshka.js.org/#Matreshka.onDebounce) – Adds an event handler which is called only once during a definite period of time - [`once`](https://matreshka.js.org/#Matreshka.once) – Adds event handler which can be called only once - [`parseBindings`](https://matreshka.js.org/#Matreshka.parseBindings) – Parses DOM tree, declaring bindings with properties enclosed in double braces - [`parseForm`](https://matreshka.js.org/#Matreshka.parseForm) – Binds named HTML form fields in a given HTML form to their corresponding properties - [`parserBrackets`](https://matreshka.js.org/#Matreshka.parserBrackets) – Contains brackets for [bindings parser](https://matreshka.js.org/#Matreshka-parseBindings) - [`remove`](https://matreshka.js.org/#Matreshka.remove) – Deletes a property - [`select`](https://matreshka.js.org/#Matreshka.select) – Returns HTML node corresponding to a selector from a sandbox - [`selectAll`](https://matreshka.js.org/#Matreshka.selectAll) – Returns HTML nodes corresponding to a selector from a sandbox - [`set`](https://matreshka.js.org/#Matreshka.set) – Sets a property value allowing to pass an event object as the third argument - [`toMatreshka`](https://matreshka.js.org/#Matreshka.toMatreshka) – The function, converting any nested tree of objects and arrays into [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) and [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instances - [`trigger`](https://matreshka.js.org/#Matreshka.trigger) – Fires an event - [`unbindNode`](https://matreshka.js.org/#Matreshka.unbindNode) – Breaks a binding between given property and HTML node --- # Matreshka#bindNode **Method** ```js Matreshka#bindNode(key, node, [binder], [eventOptions]) → object ``` Binds a property of an object to HTML node, implementing two-way data binding [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) is the only method of the [`Matreshka`](https://matreshka.js.org/#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). After using this method, it isn't necessary to monitor the synchronizations between model and view. > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.bindNode), which works just the same but accepts any object as the first argument, shifting rest arguments to the right. ```js import { bindNode } from 'matreshka'; const object = {}; bindNode(object, key, node, binder, eventOptions); // instead of this.bindNode(key, node, binder, eventOptions); ``` The method acepts three arguments: **a property name**, **HTML node** 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``, ``destroy`` (Read more here: [`binder`](https://matreshka.js.org/#type-binder)). All the five 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. ```js this.bindNode('myKey', '.my-element', { on: 'click', getValue() { ... }, setValue() { ... } }); ``` For example, you want to bind a property of an object to a ``input[type="checkbox"]`` node: ```js this.bindNode('myKey', '.my-checkbox', { // when is element state changed? // - after 'click' event on: 'click', // how to extract element state? // - return 'checked' value getValue() { return this.checked; }, // how to set element state? // - set 'checked' value setValue(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 immediately. After clicking on the checkbox, the property value will be changed to the corresponding one as well. ```js // sets checked = true this.myKey = true; ``` More complicated example: binding object property to jQuery UI widget ```html
``` ```js 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() { return $(this).slider('option', 'value'); }, // how to set element state? // - set 'value' setValue(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() { $(this).slider({ min: 0, max: 100 }); } }); ``` ```js // 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?". Indeed, there can be a lot of elements of the same type on the page: text fields, drop down menus, 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 ```bindNode``` method (see below). This problem is solved by the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) array which contains functions checking an HTML node against a set of rules and returns corresponding binder or ``undefined``. 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: ```js this.bindNode('myKey', '.my-element'); ``` How to do it? You should add a function checking your element against a set of rules to the beginning of the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) array. ```js const checkboxBinder = () => { return { on: 'click', getValue() { return this.checked; }, setValue(v) { this.checked = !!v; } } }; // the unshift method adds the function // to the beginning of the Matreshka.defaultBinders array Matreshka.defaultBinders.unshift(node => { // check if the element is a checkbox if(node.tagName == 'INPUT' && node.type == 'checkbox') { // if checking is OK, return a new binder return checkboxBinder(); } }); ``` ```js this.bindNode('myKey', '.my-checkbox'); this.myKey = true; ``` What should you do if you need to pass arguments for initializing some plugin or a widget? You can call the function that returns a binder manually. ```js const uiSlider = (min, max) => { return { on: 'slide', getValue() { return $(this).slider('option', 'value'); }, setValue(v) { $(this).slider('option', 'value', v); }, initialize() { $(this).slider({ min: min, max: max }); } } }; ``` ```js this.bindNode('myKey1', '.my-slider1', uiSlider(0, 100)); this.bindNode('myKey2', '.my-slider2', uiSlider(1, 1000)); this.myKey1 = 42; this.myKey2 = 999; ``` For global access to the binder you can add new property to [`Matreshka.binders`](https://matreshka.js.org/#Matreshka.binders). ```js Matreshka.binders.uiSlider = uiSlider; // ... this.bindNode('myKey1', '.my-slider1', Matreshka.binders.uiSlider(0, 100)); this.bindNode('myKey2', '.my-slider2', Matreshka.binders.uiSlider(1, 1000)); ``` [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) OOB 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. ```html ``` ```js 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. ```js 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: ```js this.bindNode('myKey', '.my-element'); // will handle the click on the '.my-element' element this.on('click::myKey', () => { ... }); // will handle the click on the '.my-element .my-inner-element' this.on('click::myKey(.my-inner-element)', () => { ... }); ``` > If a node is not found ``Binding error: node is missing for key "KEY"`` error will be thrown. Check out [`Matreshka#bindOptionalNode`](https://matreshka.js.org/#Matreshka-bindOptionalNode). #### Sandbox definition [`Matreshka#bindNode`](https://matreshka.js.org/#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 other HTML nodes. A special property ``sandbox`` is used for binding a sandbox. ```html
``` ```js this.bindNode('sandbox', '.my-sandbox'); ``` The definition of the sandbox adds lots of conveniences for you. For example: + allows to use the [`Matreshka#select`](https://matreshka.js.org/#Matreshka-select) and [`Matreshka#$`](https://matreshka.js.org/#Matreshka-selectAll) methods + adds a new ``:sandbox`` selector for the [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode), [`Matreshka#select`](https://matreshka.js.org/#Matreshka-select), [`Matreshka#$`](https://matreshka.js.org/#Matreshka-selectAll) methods and others + adds syntactic sugar for delegated DOM events in the [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) method > Keep in mind that you can bind only one sandbox element to ``sandbox`` property. You can try [`Matreshka#bindSandbox`](https://matreshka.js.org/#Matreshka-bindSandbox) which does the same thing but removes previous binding. ```js // 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)', () => { ... }); // will put the .inner-node element // which is inside the sandbox into the console console.log(this.$('.inner-node')); ``` ### Important features of the method and special flags The fourth argument of ``bindNode`` method is ``eventOptions``. As usual this object can include special flags or custom data which will be passed to ``bind`` and ``bind:KEY`` event handlers. ```js this.on('bind:x', evt => { console.log(evt.foo); // bar }); this.bindNode('x', node, binder, { foo: 'bar' }); ``` To understand important features of ``bindNode`` it is required to read information below but it's not required to remember all these flags. #### A flag ``exactKey=false`` If ``key`` string includes a dot then such string will be interpreted as a path to a property of nested object. Matreshka will listen all changes of given object tree. ```js this.a = { b: { c: 'foo' } }; this.bindNode('a.b.c', node); this.a.b.c = 'bar'; // updates node by bar const oldB = this.a.b; this.a.b = { c: 'baz' }; // updates node by baz // node is not updated because // the connection with the object subtree is destroyed oldB.c = 'fuu'; ``` In case if you need to use property name as is, use ``exactKey`` flag with ``true`` value. ```js this['a.b.c'] = 'foo'; this.bindNode('a.b.c', node, binder, { exactKey: true }); this['a.b.c'] = 'bar'; ``` #### A flag ``getValueOnBind`` When ``getValue`` is given then a state of an element will be extracted and assigned to bound property immediately after ``bindNode`` call in case if the property has ``undefined`` value. To force this behavior even if the property has non-undefined value use ``getValueOnbind`` flag with ``true`` value. To cancel this behavior use the same flag with ``false`` value. #### A flag ``setValueOnBind`` When ``setValue`` is given then the value of the property will be set as element state immediately after ``bindNode`` call in case if the property has non-undefined value. To force this behavior even if the property is ``undefined`` use ``setValueOnBind`` flag with ``true`` value. To cancel this behavior use the same flag but with ``false`` value. #### Flags ``debounceGetValue=true`` and ``debounceSetValue=true`` One of the most important feature of ``bindNode`` is that the logic of property change and the logic of element state change uses debounce pattern. It means that if bound property is changed many times in a short time then bound element state will be updated only once after small delay (thanks to ``debounceSetValue=true``). If element state is changed many times in a short time (eg corresponding DOM event is triggered), the property gets new value only once after minimum delay (thanks to ``debounceGetValue=true``). ```js const input = document.querySelector('.my-input'); this.bindNode('x', input); this.x = 'foo'; console.log(input.value === 'foo'); // false setTimeout(() => { console.log(input.value === 'foo'); // true }); ``` To cancel this behavior (e. g. initiate synchronous binding) use ``debounceSetValue`` and/or ``debounceGetValue`` flags with ``false`` value. #### Flags ``debounceSetValueOnBind=false`` and ``debounceGetValueOnBind=false`` As described above ``bindNode`` uses debounce pattern on property change and on bound node change. This doesn't apply to a moment when ``bindNode`` is called. To remind, when the method is called a property or a node is changed immediately. When ``debounceGetValueOnBind`` and/or ``debounceSetValueOnBind`` are set to ``true`` then debounce is turned on for binding initialization as well. #### Flags ``debounceSetValueDelay=0`` и ``debounceGetValueDelay=0`` These flags allow to set debounce delay. ``debounceSetValueDelay`` is used when ``debounceSetValue`` or ``debounceSetValueOnBind`` is ``true``, ``debounceGetValueDelay`` is used when ``debounceGetValue`` or ``debounceGetValueOnBind`` is true. #### A flag ``useExactBinder=false`` Even if you pass a binder to ``bindNode``, the framework tries to find default binder at [`Matreshka.defaultBinder`](https://matreshka.js.org/#Matreshka.defaultBinders) and extend it by properties of the passed object. This feature makes possible to use partially re-defined default binder. For example, we want to bind ``input[type="text"]`` to a property. By default, the standard binder contains ``"on"`` property with ``"input"`` value for this kind of node. It means that the value of the 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 need to pass an object containing the only ``"on"`` property as the third argument. This object will extend the default binder, having retained ``getValue`` and ``setValue`` values. ```js this.bindNode('myKey', '.my-input', { on: 'blur' }); ``` To cancel this behavior and use the binder as is, you can use ``useExactBinder`` flag with ``true`` value. ```js this.bindNode('x', node, binder, { useExactBinder: true }); ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `bind`, `bind:KEY` ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) \| [`matreshka`](https://matreshka.js.org/#type-matreshka) | A property name | | `node` | [`string`](https://matreshka.js.org/#type-string) \| [`node`](https://matreshka.js.org/#type-node) \| [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) | An HTML element which must be bound to a ``key`` | | `binder` (optional) | [`binder`](https://matreshka.js.org/#type-binder) | A binder containing the following properties: ``on`` , ``getValue``, ``setValue``, ``initialize``, ``destroy``. You can get more detailed information about binders in their documentation: see [`binder`](https://matreshka.js.org/#type-binder) | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options which accepts ``"silent"`` (don't fire ``"bind"`` and ``"bind:KEY"``), flags described above or custom data | ## Links - [`Matreshka#unbindNode`](https://matreshka.js.org/#Matreshka-unbindNode) - [`Matreshka#bindOptionalNode`](https://matreshka.js.org/#Matreshka-bindOptionalNode) - [`Matreshka#bindSandbox`](https://matreshka.js.org/#Matreshka-bindSandbox) - [`Matreshka#$`](https://matreshka.js.org/#Matreshka-selectAll) - [`Matreshka.binders`](https://matreshka.js.org/#Matreshka.binders) - [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) ## Alternative syntax: passing of an object ```js Matreshka#bindNode(bindings, [binder], [eventOptions]) → object ``` To the [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) method an object can be passed to avoid multiple invocation of the method and reduce code. Keys of the object are property names and values can get the following look: - A node - An object with properties ``node`` and ``binder`` - An array of objects with properties ``node`` and ``binder`` If ``binder`` arg is passed as the second argument then it wil be used as the binder for those elements for which a binder wasn't specified. **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `bindings` | [`object`](https://matreshka.js.org/#type-object) | (see the example) | | `binder` (optional) | [`binder`](https://matreshka.js.org/#type-binder) | (see above) | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | (see above) | ### Examples ```js this.bindNode({ foo: '.custom-checkbox', 'bar.length': 'textarea' }); ``` ```js this.bindNode({ foo: { node: ':sandbox .aaa', binder: Matreshka.binders.html() }, bar: '.bbb', baz: [{ node: '.ccc' }, { node: document.querySelector('.ddd'), binder: Matreshka.binders.prop('baz') }] }, { // will be used as a binder for .bbb and .ccc setValue(value) { foo(value); } }); ``` ## Alternative syntax which makes possible to define unlimited amount of bindings per one bindNode call. ```js Matreshka#bindNode(batch, [commonEventOptions]) → object ``` The method variation allows to pass an array of objects which need to include the following properties: - ``key`` - a property name - ``node`` - an HTML element which must be bound to a ``key`` - ``binder`` - a binder (optional) - ``event`` - event options (optional) The second arg object includes common event options for all bindings and extends ``event`` object (properties from ``event`` has more priority). **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `batch` | [`array`](https://matreshka.js.org/#type-array) | A batch of bindings | | `commonEventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Common event options | ### Examples ```js this.bindNode([{ key: 'a', node: '.my-node', binder: { setValue(v) { doSomething(v); } } }, { key: 'b', node: document.querySelectorAll('.bar'), event: { foo: 'bar' } }, { key: 'c.d.e', node: jQuery('.baz'), binder: Matreshka.binders.html(), event: { silent: true, exactKey: true } }], { getValueOnBind: false }); ``` --- # Matreshka#bindOptionalNode **Method** ```js Matreshka#bindOptionalNode() ``` Works just the same as [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) but it does not throw an exception if the ``node`` argument is an empty array, ``undefined`` or non-existent. > The method has [static alternative](https://matreshka.js.org/#Matreshka.bindOptionalNode) ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) ## Examples ```js this.bindOptionalNode('myKey', '.my-element'); ``` --- # Matreshka#calc **Method** ```js Matreshka#calc(target, source, [handler=(v)=>v], [eventOptions]) ``` Creates a dependency of one property value on values of others ``calc`` creates a dependency of a property (``target`` argument) on values of other properties (``source`` argument). When source property is changed, ``target`` is re-calculated automatically. > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.calc), which works just the same but accepts any target object as the first argument, shifting rest arguments to the right. ```js import { calc } from 'matreshka'; const object = {}; calc(object, target, source, handler, eventOptions); // instead of this.calc(target, source, handler, eventOptions); ``` ``source`` arg has few variations. #### A string A ``target`` property is dependent on ``source`` property. ```js this.b = 1; this.calc('a', 'b', b => b * 2); console.log(this.a); // 2 ``` #### An array of strings A ``target`` is dependent on properties listed at ``source`` array. ```js this.b = 1; this.c = 2; this.d = 3; this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d); console.log(this.a); // 6 ``` #### An object with properties ``object`` and ``key`` At this case ``target`` property is dependent on a property from another object. ```js const someObject = { b: 1 }; this.calc('a', { object: someObject, key: 'b' }, b => b * 2); console.log(this.a); // 2 ``` ``key`` property also accepts an array of property names. ```js const someObject = { b: 1, c: 2, d: 3 }; this.calc('a', { object: someObject, key: ['b', 'c', 'd'] }, (b, c, d) => b + c + d); console.log(this.a); // 6 ``` #### An array of object with properties ``object`` и ``key`` This variation allows to define dependency from properties of different objects. ```js const someObject = { b: 1, c: 2 }; const someObjectY = { d: 3 }; this.calc('a', [{ object: someObject, key: ['b', 'c'] }, { object: someObjectY, key: 'd' }], (b, c, d) => b + c + d); console.log(this.a); // 6 ``` #### A combination of strings (own properties) and objects ```js this.b = 1; this.c = 2; const someObject = { d: 3, e: 4 }; this.calc('a', ['b', 'c', { object: someObject, key: ['d', 'e'] }], (b, c, d, e) => b + c + d + e); console.log(this.a); // 10 ``` For reasons of code purity, the combination of strings and objects inside ``source`` array is not recommended. Instead, pass an object whose ``object`` property refers to source object. An example below makes the same job as shown at the previous example. ```js this.b = 1; this.c = 2; const someObject = { d: 3, e: 4 }; this.calc('a', [{ object: this, // the target object is "this" key: ['b', 'c'] }, { object: someObject, key: ['d', 'e'] }], (b, c, d, e) => b + c + d + e); console.log(this.a); // 10 ``` #### A path to source property If source property name includes a dot then the method initiates a dependency on a property from nested object. ```js this.b = { c: { d: 1 } }; this.e = { f: { g: 2 } }; this.calc('a', ['b.c.d', 'e.f.g'], (d, g) => d + g); console.log(this.a); // 3 ``` The same thing works for external sources. ```js this.b = { c: { d: 1 } }; const someObject = { e: { f: { g: 2 } } }; this.calc('a', [{ object: this, key: 'b.c.d' }, { object: someObject, key: 'e.f.g' }], (d, g) => d + g); console.log(this.a); // 3 ``` > 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. As you may noticed, arguments of ``handler`` function always follow the same order as source properties appear. In case if you want to change a value of one source property and make it so that target property will not be recalculated, then use [`Matreshka#set`](https://matreshka.js.org/#Matreshka-set) method with ``skipCalc`` flag. ```js this.calc('a', 'b', handler); this.set('b', newValue, { skipCalc: true }); ``` ### Important features of the method and special flags The fourth argument of ``calc`` method is ``eventOptions``. As usual this object can include special flags or custom data which will be passed to ``change:TARGET`` event handler. ```js this.on('change:a', evt => { console.log(evt.foo); // 'bar' }); this.calc('a', source, handler, { foo: 'bar' }); ``` When a source changes with the ``silent`` flag, the target changes silently too. Custom data of the source change also reaches the target's handlers. The ``force``, ``forceHTML``, ``silentHTML`` and ``skipMediator`` flags of the source change don't apply to the target. #### A flag ``debounceCalc=true`` After ``calc`` is called, target property is calculated with no delays. But when source property is changed the debounce pattern is used. That means that target property will be changed in few milliseconds and only once even if source properties was changed many times in a short time. ```js this.b = 1; this.c = 2; this.d = 3; this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d); this.on('change:a', () => { // the handler will be called only once // despite that source properties was changed thrice console.log(`a is changed to ${this.a}`); // a is changed to 60 }); this.b = 10; this.c = 20; this.d = 30; console.log(this.a); // 6 instead of 60 ``` To cancel debounce pattern when source properties are changed, in other words to make the calculation synchronously (as it was in previous versions of the method) pass ``debounceCalc`` with ``false`` value to the method. ```js this.b = 1; this.c = 2; this.d = 3; this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d, { debounceCalc: false }); this.on('change:a', () => { // the handler will be called thrice // every time when b, c or d are changed // a is changed to... 15, 33, 60 console.log(`a is changed to ${this.a}`); }); this.b = 10; this.c = 20; this.d = 30; console.log(this.a); // 60 ``` #### A flag ``debounceCalcOnInit=false`` As described above, target property is calculated immediately after the ``calc`` is called. To turn on debounce on ``calc`` call pass ``debounceCalcOnInit`` with ``true`` value to the method. ```js this.on('change:a', () => { // the handler will be called only once in a moment console.log(`a is changed to ${this.a}`); // a is changed to 6 }); this.b = 1; this.c = 2; this.d = 3; this.calc('a', ['b', 'c', 'd'], (b, c, d) => b + c + d, { debounceCalcOnInit: true }); console.log(this.a); // undefined ``` In real world ``debounceCalcOnInit`` flag is unlikely to be useful. Just keep in mind that you can enable "total debounce" if needed. #### A flag ``debounceCalcDelay=0`` The flag can be used to set debounce delay when ``debounceCalc`` or ``debounceCalcOnInit`` is set as ``true``. #### A flag ``setOnInit=true`` It is known that target property gets new value after ``calc`` is called. To cancel this behavior and don't calculate a property immediately use ``setOnInit`` with ``false`` value. ```js this.calc('a', 'b', b => b * 2, { setOnInit: false }); console.log(this.a); // undefined // but if this.b is changed the target property will be calculated this.b = 1; ``` #### A flag ``exactKey=false`` As described above, it's possible to use a path to source property using a string that contains dots. In case if you need to use exact name of source property use ``exactKey`` with ``true`` value. ```js this['foo.bar.baz'] = 1; this.calc('a', 'foo.bar.baz', fooBarBaz => fooBarBaz * 2, { exactKey: true }); console.log(this.a); // 2 ``` #### A flag ``promiseCalc=false`` This flag allows to return ``Promise`` instance from the calculating function. Target property gets its value from resolved promise. > Warning! ``Promise`` cannot be canceled. Use the ``promiseCalc`` feature carefully and don't allow multiple calls of heavy functions. If the sources change again before a promise resolves, only the latest calculation sets the target: the results of older ones are dropped. ```js this.calc('a', ['b', 'c'], (b, c) => { return new Promise(resolve => { setTimeout(() => { resolve(b + c) }, 1000); }); }, { promiseCalc: true }); this.b = 1; this.c = 2; // "a" will be changed in a second ``` ```js this.calc('response', 'data', async (data) => { const resp = await fetch(url, { method: 'post', body: data }); return resp.json(); }, { promiseCalc: true }); ``` ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `target` | | [`string`](https://matreshka.js.org/#type-string) | A property which needs to be calculated | | `source` | | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | Which properties the target property is depended on | | `handler` (optional) | `(v)=>v` | [`function`](https://matreshka.js.org/#type-function) | A function which returns a new value | | `eventOptions` (optional) | | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An object which can contain some special flags or data for ``change:KEY`` handler (see above) | ## Examples ```js this.calc('greeting', 'name', name => `Hello, ${name}!`); this.name = 'World'; // ... in a moment alert(this.greeting); // 'Hello, World!' ``` **The calculation of the rectangle perimeter with two sides known (and the calculation of the sides with the perimeter known)** ```js this.a = 3; this.b = 4; this .calc('p', ['a', 'b'], (a, b) => (a + b) * 2) .calc('a', ['p', 'b'], (p, b) => p/2 - b) .calc('b', ['p', 'a'], (p, a) => p/2 - a); alert(this.p); // 14 this.on('change:p', () => { // "The perimeter has been changed and equals 18" console.log(`The perimeter has been changed and equals ${this.p}`); }); this.a = 5; ``` ## Extra syntax for Matreshka#calc. Allows to define few calculated properties per single call of the method. ```js Matreshka#calc(batch, [commonEventOptions]) ``` The first argument is an object whose keys are property names and values are objects with the following data: - ``source`` - which properties the target property is depended on; - ``handler`` - a function which returns a new value of a property (by default it equals to ``(value) => value``); - ``event`` - event options. The second argument contains common event options which extend ``event`` of every item (properties of ``event`` have higher priority). ``source`` can take any kind of look as [described above](https://matreshka.js.org/#Matreshka-calc) (a string, an array of strings etc). ### Arguments | Name | Type | Details | | --- | --- | --- | | `batch` | [`array`](https://matreshka.js.org/#type-array) | An object which includes all information about calculated properties | | `commonEventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Event options which are common for all listed calculated properties | ### Examples ```js this.calc({ x: { source: ['a', 'b'], handler: (a, b) => a + b }, y: { source: { object: someObject, key: 'c' }, event: { setOnInit: false } }, z: { source: [{ object: this, key: 'x' }, { object: someObject, key: 'd' }], handler: (x, d) => x + d } }, { debounceCalc: false }); ``` --- # Matreshka#instantiate **Method** ```js Matreshka#instantiate(key, class, [updateCallback]) → object ``` Creates fixed class instance > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.instantiate). The method creates and fixes an instance of a class as given property value. When you try to override the property, instead of actual overriding, the instance is updated. Thus, we achieve integrity of an application, made on with Matreshka.js. > The method is an addon over [`Matreshka#mediate`](https://matreshka.js.org/#Matreshka-mediate) and it overrides a mediator. Class instance is being created during the call of ``instantiate`` 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 it at [`Matreshka.Object#setData`](https://matreshka.js.org/#Matreshka.Object-setData) method). While attempting to assign another value (an object or an array) to the property, the inner mechanism of ``instantiate`` method performs the following instead of the actual assignment: - If ``updateCallback`` function is given, the method calls it with two arguments: current property value and the data which code is trying to assign. - If given class is inherited from [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object), the instance is updated with new data using [`Matreshka.Object#setData`](https://matreshka.js.org/#Matreshka.Object-setData) method. - If given class is inherited from [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array), the instance is updated with new data using [`Matreshka.Array#recreate`](https://matreshka.js.org/#Matreshka.Array-recreate) method. - If ``updateCallback`` function isn't given and the class isn’t inherited from [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) or [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array), the instance is extended by object properties which is trying to be assigned. > A feature of this method is an absence of limitations on the class source. Any function-constructor that can be initialized using ``new`` operator and not only [`Matreshka`](https://matreshka.js.org/#Matreshka)'s successors can act as a class. **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | A key or an array of keys | | `class` | [`function`](https://matreshka.js.org/#type-function) | A class whose instance becomes the property value | | `updateCallback` (optional) | [`function`](https://matreshka.js.org/#type-function) | A 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 ```js class MyClass { // ... } // ... this.instantiate('x', MyClass); // trying to assign another value to x property this.x = { a: 42 }; // this.x is still MyClass instance alert(this.x instanceof MyClass); // true alert(this.x.a); // 42 ``` **The use of ``updateCallback``.** ```js this.instantiate('x', MyClass, (instance, data) => { updateSomeHow(instance, data); }); ``` **Getting a parent and property name. Besides data (the first argument), two arguments are passed to class constructor: a reference to an instance which has called ``instantiate`` and a name of a property.** ```js class MyClass extends Matreshka { constructor(data, parent, key) { super(); // parent is MyParentClass instance // which is created x property // key equals to "x" } } class MyParentClass extends Matreshka { constructor() { super().instantiate('x', MyClass); } } ``` **A non-standard way of using ``updateCallback`` for ignoring any changes of a property.** ```js this.instantiate('x', MyClass, () => {}); ``` **In case if your class doesn't support the use of ``new`` operator, use [`Matreshka#mediate`](https://matreshka.js.org/#Matreshka-mediate) method instead of ``instantiate``.** ```js this.mediate('x', (data, currentValue) => { return currentValue instanceof SomeClass ? Object.assign(currentValue, data) : SomeLib.initInstance(SomeClass, data); }); ``` **An abstract example with nested data (for brevity, "class instance fields" syntax is used)** ```js // app.js class App extends Matreshka { constructor(appData) { super(); this.appData = appData; this.instantiate('appData', AppData); } } // app-data.js class AppData extends Matreshka.Object { constructor(data) { super(data) .instantiate({ friends: Friends, settins: Settings }); } } // friend.js class Friend extends Matreshka.Object { constructor(data) { super(data); } } // friends.js class Friends extends Matreshka.Array { get Model() { return Friend; } trackBy = 'id'; constructor(data) { super(...data); } } // settings.js class Settings extends Matreshka.Object { constructor(data) { super(data) .instantiate('credentials', Credentials); } } // credentials.js class Credentials extends Matreshka.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 a server JSON.stringify(app.appData); // next just to assign new data to appData property // yet the object 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 }] }; ``` ## Additional syntax for Matreshka#instantiate, which accepts key-class object as the first argument. ```js Matreshka#instantiate(keyClassPairs, [updateCallback]) → object ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `keyClassPairs` | [`object`](https://matreshka.js.org/#type-object) | key-class object | | `updateCallback` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which is called at every attempt of assigning new data to a property | ### Examples ```js this.instantiate({ x: Class1, y: Class2, z: Class3 }, (instance, data) => { instance.doSomethingWith(data); }); ``` --- # Matreshka#mediate **Method** ```js Matreshka#mediate(key, mediator) → object ``` Transforms property value on its changing This method is used for transforming 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. > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.mediate), which works just the same but accepts any target object as the first argument, shifting rest arguments to the right. ```js import { mediate } from 'matreshka'; const object = {}; mediate(object, key, mediator); // instead of this.mediate(key, mediator); ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | A key or an array of keys | | `mediator` | [`function`](https://matreshka.js.org/#type-function) | A function-mediator which returns a new value. It gets the following arguments: new value, previous value, a key, an object itself | ## Examples ```js this.mediate('x', value => String(value)); this.x = 1; alert(typeof this.x); // "string" ``` **An array of keys** ```js this.mediate(['x', 'y'], value => String(value)); ``` ## Alternative syntax of the Matreshka#mediate method which accepts "key-mediator" object as an argument ```js Matreshka#mediate(keyMediatorPairs) ``` ### Arguments | Name | Type | Details | | --- | --- | --- | | `keyMediatorPairs` | [`object`](https://matreshka.js.org/#type-object) | An object with key-mediator properties | ### Examples ```js 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" ``` --- # Matreshka#off **Method** ```js Matreshka#off([names], [callback], [context]) → object ``` 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). Called without arguments, ``off`` removes every handler added with ``on``, ``once`` and ``onDebounce`` and fires ``removeevent`` for each one. Bindings, ``calc`` dependencies and the events that ``Matreshka.Object`` and ``Matreshka.Array`` use internally stay. **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `removeevent`, `removeevent:NAME` ## Arguments | Name | Type | Details | | --- | --- | --- | | `names` (optional) | [`eventNames`](https://matreshka.js.org/#type-event-names) | A list of event names which are separated by spaces (for example, ``"change:x ajaxcomplete change:y"``) | | `callback` (optional) | [`eventHandler`](https://matreshka.js.org/#type-event-handler) | A function-handler | | `context` (optional) | [`object`](https://matreshka.js.org/#type-object) | A context | ## Links - [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) - [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) - [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) - [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) ## Examples ```js this.off('change:x bind'); ``` **The deletion of all events** ```js this.off(); ``` **The deletion of an event with definite handler** ```js const handler = function() { //... } this.on('change:x', handler); this.off('change:x', handler); ``` **The deletion of an event with definite context** ```js const object = {}; this.on('change:x', handler, object); this.off('change:x', handler, object); ``` --- # Matreshka#on **Method** ```js Matreshka#on(names, callback, [triggerOnInit=false], [context]) → object ``` Adds an event handler The 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`](https://matreshka.js.org/#type-event-names). > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.on), which works just the same but accepts any target object as the first argument, shifting rest arguments to the right. ```js import { on } from 'matreshka'; const object = {}; on(object, names, callback, triggerOnInit, context); // instead of this.on(names, callback, triggerOnInit, context); ``` Adding the same handler with the same context for the same event again has no effect. DOM events (``click::x``) follow the same rule. **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `addevent`, `addevent:NAME` ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `names` | | [`eventNames`](https://matreshka.js.org/#type-event-names) | An event name or some names which are separated by a space (for example, ``"change:x ajaxcomplete change:y"``) | | `callback` | | [`eventHandler`](https://matreshka.js.org/#type-event-handler) | A function which is caused by the event | | `triggerOnInit` (optional) | `false` | [`boolean`](https://matreshka.js.org/#type-boolean) | If ``triggerOnInit`` argument equals ``true``, the handler will be called immediately after event initialization. | | `context` (optional) | | [`object`](https://matreshka.js.org/#type-object) | A context of the handler. In other words, ``this`` when called ``callback`` | ## Links - [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) - [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) - [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) - [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) ## Examples ```js this.on('foo', () => { alert('Custom Event is fired'); }); this.trigger('foo'); ``` **Passing a context** ```js this.on('foo', function() { alert(this.a); // 5 }, { a: 5 }); this.trigger('foo', 'Hello world'); ``` **Calling a handler immediately after event initialization** ```js // Displays "bar" at once and waits for a firing of "foo" event this.on('foo', () => { alert('bar'); }, true); ``` ## Alternative syntax: "eventname-handler" pairs ```js Matreshka#on(evtnameHandlerObject, [triggerOnInit=false], [context]) → object ``` In the [`Matreshka#on`](https://matreshka.js.org/#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:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `evtnameHandlerObject` | | [`object`](https://matreshka.js.org/#type-object) | An object where keys are event names and values are event handlers | | `triggerOnInit` (optional) | `false` | [`boolean`](https://matreshka.js.org/#type-boolean) | If ``triggerOnInit`` argument equals ``true``, all handlers will be called immediately after event initialization. | | `context` (optional) | | [`object`](https://matreshka.js.org/#type-object) | A context of the handler | ### Examples ```js this.on({ 'custom': evt => ..., 'click::x': evt => ..., 'change:y': evt => ..., }); ``` --- # Matreshka#once **Method** ```js Matreshka#once(names, callback, [context]) → object ``` Adds an event handler which can be called only once The method works the same as [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) but the passing handler can be called only once. > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.once) **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `addevent`, `addevent:NAME` ## Arguments | Name | Type | Details | | --- | --- | --- | | `names` | [`eventNames`](https://matreshka.js.org/#type-event-names) | An event name or some names which are separated by a space (for example, ``"change:x ajaxcomplete change:y"``) | | `callback` | [`eventHandler`](https://matreshka.js.org/#type-event-handler) | A handler which is caused by an event | | `context` (optional) | [`object`](https://matreshka.js.org/#type-object) | A context of a handler | ## Links - [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) - [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) - [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) - [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) ## Examples ```js this.x = 1; this.once('change:x', () => { alert('x is changed'); }); this.x = 2; // displays 'x is changed' this.x = 3; // does nothing ``` ## Alternative syntax: "eventname-handler" pairs ```js Matreshka#once(evtnameHandlerObject, [context]) → object ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `evtnameHandlerObject` | [`object`](https://matreshka.js.org/#type-object) | An object where keys are event names and values are event handlers | | `context` (optional) | [`object`](https://matreshka.js.org/#type-object) | A context of a handler | ### Links - [`Matreshka#on(2)`](https://matreshka.js.org/#Matreshka-on--variation-2) ### Examples ```js this.once({ 'custom': evt => { ... }, 'click::x': evt => { ... }, 'change:y': evt => { ... } }); ``` --- # Matreshka#onDebounce **Method** ```js Matreshka#onDebounce(names, callback, [debounceDelay=0], [triggerOnInit=false], [context]) → object ``` 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`](https://matreshka.js.org/#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`](https://matreshka.js.org/#Matreshka-on). > The method has [static alternative](https://matreshka.js.org/#Matreshka.onDebounce). **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `addevent`, `addevent:NAME` ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `names` | | [`eventNames`](https://matreshka.js.org/#type-event-names) | An event name or some names which are separated by a space (for example, ``"change:x ajaxcomplete change:y"``). | | `callback` | | [`eventHandler`](https://matreshka.js.org/#type-event-handler) | A handler which is caused by an event | | `debounceDelay` (optional) | `0` | [`number`](https://matreshka.js.org/#type-number) | A delay | | `triggerOnInit` (optional) | `false` | [`boolean`](https://matreshka.js.org/#type-boolean) | If ``triggerOnInit`` argument equals ``true``, the handler will be called immediately after event initialization. | | `context` (optional) | | [`object`](https://matreshka.js.org/#type-object) | A context of a handler. In other words, ``this`` when called ``callback`` | ## Links - [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) - [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) - [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) - [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) - [JavaScript Debounce Function](http://davidwalsh.name/javascript-debounce-function) ## Examples ```js this.onDebounce('change:x', () => { alert(`x = ${this.x}`); // x = 101 }, 300); this.x = 1; for(let i = 0; i < 100; i++) { this.x++; } ``` ## Alternative syntax: "eventname-handler" pairs ```js Matreshka#onDebounce(evtnameHandlerObject, [debounceDelay=0], [triggerOnInit=false], [context]) → object ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `evtnameHandlerObject` | | [`object`](https://matreshka.js.org/#type-object) | An object where keys are event names and values are event handlers | | `debounceDelay` (optional) | `0` | [`number`](https://matreshka.js.org/#type-number) | A delay | | `triggerOnInit` (optional) | `false` | [`boolean`](https://matreshka.js.org/#type-boolean) | If ``triggerOnInit`` argument equals ``true``, all handlers will be called immediately after event initialization | | `context` (optional) | | [`object`](https://matreshka.js.org/#type-object) | A context of the handler | ### Links - [`Matreshka#on(2)`](https://matreshka.js.org/#Matreshka-on--variation-2) ### Examples ```js this.onDebounce({ 'custom': evt => { ... }, 'click::x': evt => { ... }, 'change:y': evt => { ... } }); ``` --- # Matreshka#parseBindings **Method** ```js Matreshka#parseBindings(node, [eventOptions]) → $nodes ``` Parses DOM tree, declaring property bindings on which are double braced. Matreshka includes a simple DOM parser that handles double braced syntactic constructions. ``parseBindings`` method receives HTML string, DOM node or selector corresponding to DOM node as the first argument. 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 ```html Hello, {{user.name}} ``` 2. Binding form elements. ```html ``` 3. Attributes binding. ```html A link ``` > If you want to use something else instead of braces look at [`Matreshka.parserBrackets`](https://matreshka.js.org/#Matreshka.parserBrackets) #### 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](https://matreshka.js.org/#Matreshka.Array-Model). **Returns:** [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) – A collection of DOM nodes, which is passed to the method as an argument. ## Arguments | Name | Type | Details | | --- | --- | --- | | `node` | [`string`](https://matreshka.js.org/#type-string) \| [`node`](https://matreshka.js.org/#type-node) \| [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) | HTML string, selector, DOM node or collection of DOM nodes | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Event options which will be passed to all internal calls of [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) | ## Examples **Parsing of given node** ```js this.parseBindings(node); ``` **Parsing of nodes matching given selector** ```js this.parseBindings('.my-node'); ``` **HTML string parsing** ```js const $node = this.parseBindings('

Hello, {{name}}

'); this.name = 'Arthur Philip Dent'; ``` --- # Matreshka#select **Method** ```js Matreshka#select(selector) → node|null ``` Returns HTML node corresponding to a selector from a sandbox The method is very similar to [`Matreshka#selectAll`](https://matreshka.js.org/#Matreshka-selectAll), but it returns only one element or ``null``. > The method has [static alternative](https://matreshka.js.org/#Matreshka.select) **Returns:** [`node`](https://matreshka.js.org/#type-node) \| [`null`](https://matreshka.js.org/#type-null) ## Arguments | Name | Type | Details | | --- | --- | --- | | `selector` | [`string`](https://matreshka.js.org/#type-string) | A selector | ## Examples ```js this.bindNode('sandbox', '.app'); this.select('.my-element'); // the same as this.nodes.sandbox.querySelector('.my-element'); // the same as $('.app').find('.my-element')[0]; ``` --- # Matreshka#selectAll **Method** ```js Matreshka#selectAll(selector) → $nodes ``` Returns HTML nodes corresponding to a selector from a sandbox Synonym: `Matreshka#$` After sandbox declaration using [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) method, you can get its descendants. Besides, the method supports the ``:bound(KEY)`` selector. > The method has [static alternative](https://matreshka.js.org/#Matreshka.selectAll) **Returns:** [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) ## Arguments | Name | Type | Details | | --- | --- | --- | | `selector` | [`string`](https://matreshka.js.org/#type-string) | A selector | ## Examples ```js this.bindNode('sandbox', '.app'); nodes = this.selectAll('.my-element'); // the same as nodes = this.$('.my-element'); // $ is a short reference to selectAll // the same as nodes = $('.app').find('.my-element'); ``` **The ``:bound(KEY)`` selector** ```js this.bindNode('myKey', '.my-element'); nodes = this.selectAll(':bound(myKey) .my-another-element'); // the same as nodes = $('.my-element').find('.my-another-element'); ``` --- # Matreshka#set **Method** ```js Matreshka#set(key, value, [eventOptions]) ``` Sets a property value allowing to pass event options 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`](https://matreshka.js.org/#Matreshka-mediate)) + ``skipCalc`` - prevents the work of dependencies created with [`Matreshka#calc`](https://matreshka.js.org/#Matreshka-calc) > The method has [static alternative](https://matreshka.js.org/#Matreshka.set). **Fires:** `change`, `change:KEY`, `beforechange`, `beforechange:KEY` ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) | A key | | `value` | [`*`](https://matreshka.js.org/#type-any) | A value | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Event options | ## Examples ```js this.on('change:myKey', evt => { alert(evt.value); }); // the same as this['myKey'] = 3 // or this.myKey = 3 // alerts 3 this.set('myKey', 3); ``` **Using ``eventOptions``** ```js this.on('change:myKey', evt => { alert(evt.value); }); // handler isn't called this.set('myKey', 4, { silent: true }); ``` **Passing custom data to a handler** ```js this.on('change:myKey', evt => { alert(evt.myCustomFlag); }); // alerts 42 this.set('myKey', 4, { myCustomFlag: 42 }); ``` ## Alternative "key-value" syntax of the Matreshka#set method ```js Matreshka#set(keyValuePairs, [eventOptions]) ``` ### Arguments | Name | Type | Details | | --- | --- | --- | | `keyValuePairs` | [`object`](https://matreshka.js.org/#type-object) | An object containing key-value pairs | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event object | ### Examples ```js this.set({ myKey1: 1, myKey2: 2 }); ``` **Passing ``eventOptions`` as second argument** ```js this.set({ myKey: 3 }, { myFlag: 'foo' }); ``` --- # Matreshka#trigger **Method** ```js Matreshka#trigger(names, [arg]) → matreshka ``` Fires an event After adding event handlers using [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on), [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) or [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once), any event can be fired manually using this method. > Note that the method has [static alternative](https://matreshka.js.org/#Matreshka.trigger) **Returns:** [`matreshka`](https://matreshka.js.org/#type-matreshka) – self ## Arguments | Name | Type | Details | | --- | --- | --- | | `names` | [`eventNames`](https://matreshka.js.org/#type-event-names) | An event name or some names which are separated by a space | | `arg` (optional) | `...*` | Any arguments which will be passed to every handler | ## Links - [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) - [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) - [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) - [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) ## Examples ```js this.on('foo bar', (a, b, c) => { alert(a + b + c); }); this.trigger('foo', 1, 2, 3); // alerts 6 ``` --- # Matreshka#unbindNode **Method** ```js Matreshka#unbindNode(key, [node], [eventOptions]) → object ``` Destroys 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. A key with dots is a path to a nested property, as in [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode); with the ``exactKey: true`` event option it is used as is. ``null`` as the key also removes the bindings of nested properties (``"a.b"``). **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `unbind`, `unbind:KEY` ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) \| [`null`](https://matreshka.js.org/#type-null) | A key or an array of keys. If you pass ``null`` instead of the key, all bindings for the given instance will be deleted | | `node` (optional) | [`string`](https://matreshka.js.org/#type-string) \| [`node`](https://matreshka.js.org/#type-node) \| [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) | HTML node | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Event object (``"silent"`` key disables firing the events ``"unbind"`` and ``"unbind:KEY"``) | ## Examples ```js 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; ``` ## Alternative syntax which allows to pass an object with bindings to unbindNode. Look at Matreshka#bindNode(2) for more information ```js Matreshka#unbindNode(bindings, [eventOptions]) → object ``` **Returns:** [`object`](https://matreshka.js.org/#type-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `bindings` | [`object`](https://matreshka.js.org/#type-object) | (see the example) | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | (see above) | ### Examples ```js this.unbindNode({ foo: '.aaa', bar: { node: '.bbb' }, baz: [{ node: '.ccc' }, { node: '.ddd' }] }); ``` ## Alternative syntax of the method which allows to easily unbind unlimited amount of bindings by single unbindNode call. ```js Matreshka#unbindNode(batch, [eventOptions]) ``` The variation makes possible to pass an array which includes objects with the following properties: - ``key`` - a property name - ``node`` - a node bound to ``key`` (optional) This variation is useful because it matches one variation of [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) method, allowing to store bindings in a variable to easily remove them when needed. ### Arguments | Name | Type | Details | | --- | --- | --- | | `batch` | [`array`](https://matreshka.js.org/#type-array) | An array of bindings | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | (see above) | ### Examples ```js const temporaryBindings = [{ key: 'a', node: '.my-node', binder: { setValue(v) { doSomething(v); } } }, { key: 'b', node: document.querySelectorAll('.bar'), event: { foo: 'bar' } }, { key: 'c.d.e', node: jQuery('.baz'), binder: Matreshka.binders.html(), event: { silent: true, exactKey: true } }] this.bindNode(temporaryBindings); // these bindings are no longer needed this.unbindNode(temporaryBindings); ``` --- # Matreshka#bindSandbox **Method** ```js Matreshka#bindSandbox(node, [eventOptions]) ``` Binds a sandbox Unbinds previous sandbox (if exists) and binds new one. > The method has [static alternative](https://matreshka.js.org/#Matreshka.bindSandbox) The ``sandbox`` key is reserved for the binding: it is left out of ``Object.keys`` and ``JSON.stringify``, and reading or assigning ``this.sandbox`` throws an error. The bound node is ``this.nodes.sandbox``. **Fires:** `bind`, `bind:sandbox` ## Arguments | Name | Type | Details | | --- | --- | --- | | `node` | [`string`](https://matreshka.js.org/#type-string) \| [`node`](https://matreshka.js.org/#type-node) \| [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) | A sandbox DOM node | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options | ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) ## Examples ```js this.bindSandbox('.my-element'); ``` --- # Matreshka#remove **Method** ```js Matreshka#remove(key, [eventOptions]) → object ``` Deletes a property > The method has [static alternative](https://matreshka.js.org/#Matreshka.remove) **Returns:** [`object`](https://matreshka.js.org/#type-object) – self **Fires:** `delete`, `delete:KEY` ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) | A property name or an array of names to remove | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options | ## Examples ```js this.remove('myKey'); this.remove(['myKey1', 'myKey2']); ``` **Using ``eventOptions``** ```js this.remove('myKey', { silent: true }); ``` --- # Matreshka#$nodes **Property** ```js Matreshka#$nodes: $nodes ``` An object contains arrays of bound nodes for quick access. ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) ## Examples ```js this.bindNode('myKey', '.my-node'); this.$nodes.myKey; // an array of the nodes, like Array.from(document.querySelectorAll('.my-node')) ``` --- # Matreshka#isMatreshka **Property** ```js Matreshka#isMatreshka: boolean ``` ``isMatreshka`` always equals ``true`` for instances of [`Matreshka`](https://matreshka.js.org/#Matreshka) ## Examples ```js alert(object.isMatreshka); ``` --- # Matreshka#nodes **Property** ```js Matreshka#nodes: node ``` 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`](https://matreshka.js.org/#Matreshka-$nodes) for getting all the nodes bound to a certain property. ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) ## Examples ```js this.bindNode('myKey', '.my-node'); this.nodes.myKey; // the same as $('.my-node')[0] ``` --- # Matreshka.bindNode **Method** **Import:** ```js import { bindNode } from 'matreshka'; ``` ```js Matreshka.bindNode() → object ``` Binds a property of an object to HTML node, implementing two-way data binding This static method works the same as [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) ## Examples ```js const object = {}; Matreshka.bindNode(object, 'x', '.my-node'); ``` --- # Matreshka.calc **Method** **Import:** ```js import { calc } from 'matreshka'; ``` ```js Matreshka.calc() → object ``` Creates a dependency of one property value on values of others This static method works the same as [`Matreshka#calc`](https://matreshka.js.org/#Matreshka-calc) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#calc`](https://matreshka.js.org/#Matreshka-calc) ## Examples ```js const object = {}; object.a = 40; object.b = 2; Matreshka.calc(object, 'sum', ['a', 'b'], (a, b) => a + b); alert(object.sum); // 42 ``` --- # Matreshka.chain **Method** **Import:** ```js import { chain } from 'matreshka'; ``` ```js Matreshka.chain(object) → object ``` Allows chained calls of universal methods The function accepts any object and returns an instance of externally inaccessible class which adopts universal methods allowing them to be called in a chain to change given object. > Universal method is a method which exist at [`Matreshka`](https://matreshka.js.org/#Matreshka) prototype and have a static alternative (e. g. [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) and [`Matreshka.bindNode`](https://matreshka.js.org/#Matreshka.bindNode)) **Returns:** [`object`](https://matreshka.js.org/#type-object) – An instance of the class which adopts universal methods ## Arguments | Name | Type | Details | | --- | --- | --- | | `object` | [`object`](https://matreshka.js.org/#type-object) \| [`function`](https://matreshka.js.org/#type-function) | An object | ## Examples ```js const object = {}; Matreshka.chain(object) .calc('a', 'b', b => b * 2) .set('b', 3) .bindNode('c', '.node'); // the same as // Matreshka.calc(object, 'a', 'b', b => b * 2) // Matreshka.set(object, 'b', 3) // Matreshka.bindNode(object, 'c', '.node'); ``` --- # Matreshka.Class **Method** **Import:** ```js import { Class } from 'matreshka'; ``` ```js Matreshka.Class(prototype, [statics]) → class ``` An implementation of classes based on the prototype inheritance The ``Class`` function allows to use the classic OOP when ECMAScript 2015 classes cannot be used somehow. If ``prototype`` has no own ``constructor`` property, the class calls the parent constructor with the same arguments, like an ECMAScript 2015 class without a constructor. An ECMAScript 2015 class can be passed as ``constructor``: it runs on instantiation, but the methods declared in its body are not inherited; put them in ``prototype``. **Returns:** [`class`](https://matreshka.js.org/#type-class) – class (a class constructor to be exact) ## Arguments | Name | Type | Details | | --- | --- | --- | | `prototype` | [`object`](https://matreshka.js.org/#type-object) | Methods and properties | | `statics` (optional) | [`object`](https://matreshka.js.org/#type-object) | Static methods and properties | ## Examples ```js const A = Matreshka.Class({ method1() { ... } }); const B = Matreshka.Class({ // B is inherited from A extends: A, method2() { ... } }); const C = Matreshka.Class({ // С is inherited from B extends: B, method2() { // calling the parent method B.prototype.method2.apply(this, arguments); }, method3(a, b) { ... } }); const D = Matreshka.Class({ // D is inherited from C extends: C, method3() { // calling the parent method C.prototype.method3.apply(this, arguments); } }); ``` **Passing an object with static methods and properties** ```js const MyClass = Matreshka.Class({ method() { ... } }, { staticProp: 'foo', staticMethod() { return 'bar'; } }); alert(MyClass.staticProp); // foo alert(MyClass.staticMethod()); // bar ``` --- # Matreshka.mediate **Method** **Import:** ```js import { mediate } from 'matreshka'; ``` ```js Matreshka.mediate() → object ``` Transforms property value on its changing This static method works the same as [`Matreshka#mediate`](https://matreshka.js.org/#Matreshka-mediate) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#mediate`](https://matreshka.js.org/#Matreshka-mediate) ## Examples ```js const object = {}; Matreshka.mediate(object, 'x', String); object.x = 42; alert(typeof object.x); // string ``` --- # Matreshka.on **Method** **Import:** ```js import { on } from 'matreshka'; ``` ```js Matreshka.on() → object ``` Adds an event handler This static method works the same as [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) ## Examples ```js const object = {}; Matreshka.on(object, 'foo', evt => { alert(evt.hello); }); Matreshka.trigger(object, 'foo', { hello: 'World' }); ``` --- # Matreshka.bindOptionalNode **Method** **Import:** ```js import { bindOptionalNode } from 'matreshka'; ``` ```js Matreshka.bindOptionalNode() → object ``` Initializes two-way data binding but does not throws an exception if ``node`` argument is an empty array, ``undefined`` or non-existent This static method works the same as [`Matreshka#bindOptionalNode`](https://matreshka.js.org/#Matreshka-bindOptionalNode) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#bindOptionalNode`](https://matreshka.js.org/#Matreshka-bindOptionalNode) ## Examples ```js const object = {}; Matreshka.bindOptionalNode(object, 'x', '.my-node'); ``` --- # Matreshka.bindSandbox **Method** **Import:** ```js import { bindSandbox } from 'matreshka'; ``` ```js Matreshka.bindSandbox() → object ``` Binds or re-binds sandbox node This static method works the same as [`Matreshka#bindSandbox`](https://matreshka.js.org/#Matreshka-bindSandbox) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#bindSandbox`](https://matreshka.js.org/#Matreshka-bindSandbox) ## Examples ```js const object = {}; Matreshka.bindSandbox(object, '.my-node'); ``` --- # Matreshka.instantiate **Method** **Import:** ```js import { instantiate } from 'matreshka'; ``` ```js Matreshka.instantiate() → object ``` Creates fixed class instance This static method works the same as [`Matreshka#instantiate`](https://matreshka.js.org/#Matreshka-instantiate) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#instantiate`](https://matreshka.js.org/#Matreshka-instantiate) ## Examples ```js const object = {}; Matreshka.instantiate(object, 'x', SomeClass); object.x = { a: 42 }; alert(object.x instanceof SomeClass); // true alert(object.x.a); // 42 ``` --- # Matreshka.initRouter **Method** **Import:** ```js import { initRouter } from 'matreshka/router'; ``` ```js Matreshka.initRouter(object, route, [type="hash"]) → object ``` Turns on two-way data binding between properties and parts of the URL The router is hash-based by default: it uses ``location.hash`` with a hashbang (``#!/a/b/``). Pass ``"history"`` as the third argument to use the path (``/a/b/``) through the History API instead. ```js // location.hash is used there initRouter(object, '/a/b/c/'); object.a = 'foo'; object.b = 'bar'; object.c = 'baz'; // makes location.hash to be #!/foo/bar/baz/ ``` If you need to use History API instead of hash, pass ``"history"`` as the third argument. ```js initRouter(object, '/a/b/c/', 'history'); ``` How does "traditional" routing work? A developer defines a rule (route) and defines a function which will be called when current path fits given rule. ```js route("books/:id", id => { // do something }); ``` The principle of ``initRouter`` is different. You define which part of URL (both [hash](https://developer.mozilla.org/en-US/docs/Web/API/Location/hash), and [HTML5 History](https://developer.mozilla.org/en-US/docs/Web/API/History_API) are supported) need to be synchronized with given property. Let's say you need to synchronize ``"x"`` with the first part of ``location.hash`` and ``"y"`` with the second. ```js initRouter(object, '/x/y/'); ``` Now when you type... ```js object.x = 'foo'; object.y = 'bar'; ``` ...``location.hash`` is automatically changed to ``#!/foo/bar/`` And vice versa. When the URL is changed manually or via back and forward buttons, the properties will be changed automatically. ```js location.hash = '#!/baz/qux/'; // ... after a moment console.log(object.x, object.y); // 'baz', 'qux' ``` As usually you can listen property changes with [`Matreshka#on`](https://matreshka.js.org/#Matreshka-on) method. ```js Matreshka.on(object, 'change:x', handler); // for Matreshka instances: this.on('change:x', handler); ``` Values are encoded in the URL and decoded back: ``object.x = 'a b/c'`` gives ``#!/a%20b%2Fc/``, and ``object.x`` stays ``'a b/c'``. A hash which doesn't start with ``#!`` (an anchor such as ``#top``) is not a route. #### An asterisk syntax You can pass a string which contain asterisks to ``initRouter`` if you don't need to synchronize some part of the path with a property. ```js initRouter(object, '/x/*/y'); ``` If the hash looks like ``#!/foo/bar/baz/``, then ``object.x = "foo"`` and ``object.y = "baz"``. This feature is useful in cases when classes control different parts of the path. **class1.js** ```js initRouter(this, '/x/*/'); ``` **class2.js** ```js initRouter(this, '/*/y/'); ``` #### Two things to remember **1.** If a property has a value (not ``undefined``, ``null`` or ``''``) then URL will be changed immediately after ``initRouter`` call. A property without a value gets its value from the URL. ```js object.x = 'foo'; initRouter(object, '/x/y/'); ``` **2.** If a property gets ``null``, ``undefined`` or ``''`` then all next listed properties will get ``null`` as new value. ```js initRouter(object, '/x/y/z/u/'); object.y = null; // makes object.z and object.u to be null as well ``` The idea is to get actual state of URL. It could be weird to get ``"z"`` with value ``"foo"`` in case of non-existing bound part of URL. #### HTML5 History API The router supports HTML5 History as well. To initialize it you need to pass optional argument ``type`` with ``"history"`` value to the ``initRouter`` function (by default ``type`` is ``"hash"``). ```js initRouter(object, '/x/y/z/', 'history'); ``` The router reads and writes ``location.pathname``; the query string and the hash stay as they are. > In a page with the script tag bundle the function is ``Matreshka.initRouter``. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `object` | | [`object`](https://matreshka.js.org/#type-object) | An object | | `route` | | [`string`](https://matreshka.js.org/#type-string) | A route: property names separated by slashes, ``*`` for a part which isn't synchronized | | `type` (optional) | `"hash"` | [`string`](https://matreshka.js.org/#type-string) | ``"hash"`` or ``"history"`` | ## Links - [`Matreshka.Router`](https://matreshka.js.org/#Matreshka.Router) - [Router example](https://matreshka.js.org/examples/router/) --- # Matreshka.lookForBinder **Method** **Import:** ```js import { lookForBinder } from 'matreshka'; ``` ```js Matreshka.lookForBinder(node) → binder ``` Returns a binder corresponding to an element. If it is not found, it returns ``undefined``. The function uses [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) for the search. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) – binder ## Arguments | Name | Type | Details | | --- | --- | --- | | `node` | [`node`](https://matreshka.js.org/#type-node) | | ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) - [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) ## Examples ```js const element = document.createElement('input'); element.type = 'text'; console.log(Matreshka.lookForBinder(element)); // will return something similar to the following object { on: 'input', getValue() { return this.value; }, setValue(v) { this.value = v; } } ``` --- # Matreshka.off **Method** **Import:** ```js import { off } from 'matreshka'; ``` ```js Matreshka.off() → object ``` Deletes an event handler This static method works the same as [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) and all its variations, but accepts any kind of JavaScript object as first argument. Called with the object only, it removes every handler added with ``on``, ``once`` and ``onDebounce``; bindings and ``calc`` dependencies stay. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#off`](https://matreshka.js.org/#Matreshka-off) ## Examples ```js const object = {}; Matreshka.on(object, 'foo', evt => { //... }); Matreshka.off(object, 'foo'); ``` --- # Matreshka.once **Method** **Import:** ```js import { once } from 'matreshka'; ``` ```js Matreshka.once() → object ``` Adds event handler which can be called only once This static method works the same as [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#once`](https://matreshka.js.org/#Matreshka-once) ## Examples ```js const object = {}; Matreshka.once(object, 'foo', evt => { //... }); ``` --- # Matreshka.onDebounce **Method** **Import:** ```js import { onDebounce } from 'matreshka'; ``` ```js Matreshka.onDebounce() → object ``` Adds an event handler which is called only once during a definite period of time This static method works the same as [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#onDebounce`](https://matreshka.js.org/#Matreshka-onDebounce) ## Examples ```js const object = {}; Matreshka.onDebounce(object, 'foo', evt => { //... }); ``` --- # Matreshka.parseBindings **Method** **Import:** ```js import { parseBindings } from 'matreshka'; ``` ```js Matreshka.parseBindings() → $nodes ``` Parses DOM tree, declaring bindings with properties enclosed in double braces This static method works the same as [`Matreshka#parseBindings`](https://matreshka.js.org/#Matreshka-parseBindings) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) – Resulting collection of DOM nodes ## Links - [`Matreshka#parseBindings`](https://matreshka.js.org/#Matreshka-parseBindings) ## Examples ```js const object = {}; const $node = Matreshka.parseBindings(object, `

Hello, {{name}}

`); object.name = 'World'; ``` --- # Matreshka.parseForm **Method** **Import:** ```js import { parseForm } from 'matreshka/parse-form'; ``` ```js Matreshka.parseForm(object, form, [callback], [eventOptions]) → node|null ``` The function binds named HTML form fields (input, select, textarea, etc.) in a given HTML form to their corresponding properties. ```html
``` ```js const object = {}; parseForm(object, '.my-form'); // ... console.log(object.x); // 'foo' object.x = 'bar'; // changes input value to 'bar' ``` The third argument is useful when ``parseForm`` is used with [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object): you can call [`Matreshka.Object#addDataKeys`](https://matreshka.js.org/#Matreshka.Object-addDataKeys) method there. ```js const form = parseForm(this, ':sandbox .foo', key => this.addDataKeys(key), { getValueOnBind: false }); ``` > In a page with the script tag bundle the function is ``Matreshka.parseForm``. **Returns:** [`node`](https://matreshka.js.org/#type-node) \| [`null`](https://matreshka.js.org/#type-null) – The parsed form element, or ``null`` if the form isn't found ## Arguments | Name | Type | Details | | --- | --- | --- | | `object` | [`object`](https://matreshka.js.org/#type-object) | An object | | `form` | [`string`](https://matreshka.js.org/#type-string) \| [`node`](https://matreshka.js.org/#type-node) \| [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) | A selector, DOM node, etc. of the given form (custom selectors ``:sandbox`` and ``:bound(KEY)`` also acceptable) | | `callback` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which will be called on every found field; accepts field name and field element itself | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | Event options which will be passed to every internal call of [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) | ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) - [Form parser example](https://matreshka.js.org/examples/parse-form/) --- # Matreshka.remove **Method** **Import:** ```js import { remove } from 'matreshka'; ``` ```js Matreshka.remove() → object ``` Deletes a property This static method works the same as [`Matreshka#remove`](https://matreshka.js.org/#Matreshka-remove) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#remove`](https://matreshka.js.org/#Matreshka-remove) ## Examples ```js Matreshka.remove(object, 'x'); ``` --- # Matreshka.select **Method** **Import:** ```js import { select } from 'matreshka'; ``` ```js Matreshka.select() → node|null ``` Returns HTML node corresponding to a selector from a sandbox This static method works the same as [`Matreshka#select`](https://matreshka.js.org/#Matreshka-select) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`node`](https://matreshka.js.org/#type-node) \| [`null`](https://matreshka.js.org/#type-null) ## Links - [`Matreshka#select`](https://matreshka.js.org/#Matreshka-select) ## Examples ```js const object = {}; Matreshka.bindNode(object, 'sandbox', '.app'); Matreshka.select(object, '.my-element'); ``` --- # Matreshka.selectAll **Method** **Import:** ```js import { selectAll } from 'matreshka'; ``` ```js Matreshka.selectAll() → $nodes ``` Returns HTML nodes corresponding to a selector from a sandbox This static method works the same as [`Matreshka#selectAll`](https://matreshka.js.org/#Matreshka-selectAll) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`$nodes`](https://matreshka.js.org/#type-dollar-nodes) ## Links - [`Matreshka#selectAll`](https://matreshka.js.org/#Matreshka-selectAll) ## Examples ```js const object = {}; Matreshka.bindNode(object, 'sandbox', '.app'); Matreshka.selectAll(object, '.my-element'); ``` --- # Matreshka.set **Method** **Import:** ```js import { set } from 'matreshka'; ``` ```js Matreshka.set() → object ``` Sets a property value allowing to pass an event object as the third argument This static method works the same as [`Matreshka#set`](https://matreshka.js.org/#Matreshka-set) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#set`](https://matreshka.js.org/#Matreshka-set) ## Examples ```js const object = {}; Matreshka.set(object, 'x', 42, { someOption: true }); ``` --- # Matreshka.toMatreshka **Method** **Import:** ```js import { toMatreshka } from 'matreshka'; ``` ```js Matreshka.toMatreshka() → matreshka ``` The function, converting any nested tree of objects and arrays into [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) and [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instances Only arrays and ``Matreshka.Array`` instances become ``Matreshka.Array``; every other object, even one with a ``length`` property, becomes ``Matreshka.Object``. A ``Matreshka.Object`` passed in gives only its data keys. **Returns:** [`matreshka`](https://matreshka.js.org/#type-matreshka) – a newly created instance of ``Matreshka`` ## Examples ```js const matreshka = Matreshka.toMatreshka({ a: 1, b: { c: 2 }, d: [{e: 1}, {e: 2}, {e: 3}] }); ``` --- # Matreshka.trigger **Method** **Import:** ```js import { trigger } from 'matreshka'; ``` ```js Matreshka.trigger() → object ``` Fires an event This static method works the same as [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) ## Examples ```js const object = {}; Matreshka.on(object, 'foo', evt => { alert(evt.hello); }); Matreshka.trigger(object, 'foo', { hello: 'World' }); ``` --- # Matreshka.unbindNode **Method** **Import:** ```js import { unbindNode } from 'matreshka'; ``` ```js Matreshka.unbindNode() → object ``` Breaks a binding between given property and HTML node This static method works the same as [`Matreshka#unbindNode`](https://matreshka.js.org/#Matreshka-unbindNode) and all its variations, but accepts any kind of JavaScript object as first argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) – The first argument ## Links - [`Matreshka#unbindNode`](https://matreshka.js.org/#Matreshka-unbindNode) ## Examples ```js const object = {}; Matreshka.unbindNode(object, 'x', '.my-node'); ``` --- # Matreshka.defaultBinders **Property** **Import:** ```js import { defaultBinders } from 'matreshka'; ``` ```js Matreshka.defaultBinders: array ``` An array of functions which return a corresponding binder ``defaultBinders`` is the array of functions which check an element in turn against given rules in these functions and return a binder (see [`binder`](https://matreshka.js.org/#type-binder)). This array is used when the third argument has not been passed to the [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) method. See more detailed information about bindings in [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) documentation. ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) - [`Matreshka.lookForBinder`](https://matreshka.js.org/#Matreshka.lookForBinder) ## Examples ```js Matreshka.defaultBinders.unshift(element => { // check if the element has "foo" class name if(element.classList.contains('foo')) { // if checking is OK, return a new binder return { on: ..., getValue: ..., setValue: ... }; } }); // ... this.bindNode('myKey', '.foo.bar'); ``` --- # Matreshka.parserBrackets **Property** **Import:** ```js import { parserBrackets } from 'matreshka'; ``` ```js Matreshka.parserBrackets: object ``` Contains brackets for [bindings parser](https://matreshka.js.org/#Matreshka-parseBindings) ``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) Any characters can be used as brackets. ## Examples **Use syntax ``[[=property]]`` instead of ``{{property}}``** ```js Matreshka.parserBrackets.left = '[[='; Matreshka.parserBrackets.right = ']]'; ``` --- # Matreshka.Object **Class** · extends `Matreshka` **Import:** ```js import { MatreshkaObject } from 'matreshka'; ``` ``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`](https://matreshka.js.org/#Matreshka) class and includes all its properties and methods. Imagine you create an object which includes ``"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`](https://matreshka.js.org/#Matreshka.Object-addDataKeys) method. ```js 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#setData`](https://matreshka.js.org/#Matreshka.Object-setData) method, which declares not only properties responsible for data but sets their values at once. ```js this.setData({ a: 1, b: 2 }); this.c = 3; ``` After an application has found out what is data, [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) instance can be converted into an ordinary object by the [`Matreshka.Object#toJSON`](https://matreshka.js.org/#Matreshka.Object-toJSON) method and passed to a server or kept in a local DB (for example, in ``localStorage``). ```js // will return an object { a: 1, b: 2 } this.toJSON(); ``` #### Events On add or change of data properties ``set`` and ``modify`` events are fired. On remove of data properties ``remove`` and ``modify`` events are fired. That means you can listen any changes of ``Matreshka.Object`` instance with the only ``modify`` event name. ```js this.on('modify', () => { alert('an object is modified'); }); ``` ## Arguments | Name | Type | Details | | --- | --- | --- | | `data` (optional) | [`object`](https://matreshka.js.org/#type-object) | Data | ## Examples **Creation of an instance with two specified properties** ```js // the same as new Matreshka.Object().setData({ a: 1, b: 2 }); new Matreshka.Object({ a: 1, b: 2 }); ``` **The inheritance** ```js class MyClass extends Matreshka.Object { constructor(data) { super(data).sayHello(); } sayHello() { alert("Hello World!"); } } ``` **The inheritance using [`Matreshka.Class`](https://matreshka.js.org/#Matreshka.Class) function** ```js const MyClass = Matreshka.Class({ extends: Matreshka.Object, constructor(data) { this.setData(data).sayHello(); }, sayHello() { alert("Hello World!"); } }); ``` **Data enumerating, using for..of** ```js const matreshkaObject = new Matreshka.Object({ a: 1, b: 2 }); for(let item of matreshkaObject) { console.log(item); // 1 .. 2 } ``` ## Methods and properties - [`addDataKeys`](https://matreshka.js.org/#Matreshka.Object-addDataKeys) – Adds given property names to a list of property names which are responsible for data - [`each`](https://matreshka.js.org/#Matreshka.Object-each) – Iterates properties which are responsible for data through ``callback`` function - [`entries`](https://matreshka.js.org/#Matreshka.Object-entries) – Returns an array of ``[key, value]`` pairs of properties which are responsible for data - [`isDataKey`](https://matreshka.js.org/#Matreshka.Object-isDataKey) – Checks if given string a name of data property - [`isMatreshkaObject`](https://matreshka.js.org/#Matreshka.Object-isMatreshkaObject) – The ``isMatreshkaObject`` property always equals ``true`` for instances of [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) class - [`keyOf`](https://matreshka.js.org/#Matreshka.Object-keyOf) – Searches for specified property value among others which are responsible for data and returns one key if this value has been found (very similar to ``Array.prototype.indexOf`` function) - [`keys`](https://matreshka.js.org/#Matreshka.Object-keys) – Returns an array of property names which are responsible for data - [`removeDataKeys`](https://matreshka.js.org/#Matreshka.Object-removeDataKeys) – Deletes given property names from a list of property names which are responsible for data (but does not delete the properties) - [`setData`](https://matreshka.js.org/#Matreshka.Object-setData) – Sets a property and adds property name to a list of property names which are responsible for data - [`toJSON`](https://matreshka.js.org/#Matreshka.Object-toJSON) – Converts an instance and its internal properties into an ordinary object - [`values`](https://matreshka.js.org/#Matreshka.Object-values) – Returns an array of property values which are responsible for data --- # Matreshka.Object#addDataKeys **Method** ```js Matreshka.Object#addDataKeys(keys) → matreshkaObject ``` Adds given property names to a list of property names 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`](https://matreshka.js.org/#type-matreshka-object) – self **Fires:** `set`, `modify` ## Arguments | Name | Type | Details | | --- | --- | --- | | `keys` | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | An array of property names or a list of args | ## Examples ```js this.addDataKeys(['a', 'b']); ``` ```js this.addDataKeys('a', 'b'); ``` --- # Matreshka.Object#each **Method** ```js 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``. It allows to iterate over data properties when for..of syntax is not available. **Returns:** [`matreshkaObject`](https://matreshka.js.org/#type-matreshka-object) – self ## Arguments | Name | Type | Details | | --- | --- | --- | | `callback` | [`function`](https://matreshka.js.org/#type-function) | A function which is called on every iteration | | `thisArg` (optional) | [`*`](https://matreshka.js.org/#type-any) | A context of a function | ## Examples ```js this .setData({ a: 1, b: 2 }) .addDataKeys('c') .each((value, key) => { console.log(key, value); }, this); ; // >>> a 1, b 2, c undefined ``` --- # Matreshka.Object#isDataKey **Method** ```js Matreshka.Object#isDataKey(key) → boolean ``` Checks if given string a name of data property **Returns:** [`boolean`](https://matreshka.js.org/#type-boolean) – a result of checking ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) | | ## Examples ```js console.log(this.isDataKey('a')); ``` --- # Matreshka.Object#keyOf **Method** ```js Matreshka.Object#keyOf() → string|null ``` Searches for specified property value among others which are responsible for data and returns one key if this value has been found (very similar to ``Array.prototype.indexOf`` function) **Returns:** [`string`](https://matreshka.js.org/#type-string) \| [`null`](https://matreshka.js.org/#type-null) ## Properties | Name | Type | Details | | --- | --- | --- | | `value` | [`*`](https://matreshka.js.org/#type-any) | A value of any type which should be found among data keys | ## Examples ```js const matreshkaObject = new Matreshka.Object({ a: 1, b: 2 }); matreshkaObject.c = 3; matreshkaObject.keyOf(1); // 'a' matreshkaObject.keyOf(2); // 'b' matreshkaObject.keyOf(3); // null ``` --- # Matreshka.Object#keys **Method** ```js Matreshka.Object#keys() → array ``` Returns an array of property names which are responsible for data **Returns:** [`array`](https://matreshka.js.org/#type-array) – keys ## Examples ```js const keys = this.keys(); ``` --- # Matreshka.Object#removeDataKeys **Method** ```js Matreshka.Object#removeDataKeys(keys) → matreshkaObject ``` Deletes given property names from a list of property names which are responsible for data (but does not delete the properties) The ``remove`` event fires before ``modify``, as with [`Matreshka#remove`](https://matreshka.js.org/#Matreshka-remove). **Returns:** [`matreshkaObject`](https://matreshka.js.org/#type-matreshka-object) – self **Fires:** `remove`, `modify` ## Arguments | Name | Type | Details | | --- | --- | --- | | `keys` | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | An array of property names or a list of args | ## Examples ```js this.removeDataKeys(['a', 'b']); ``` ```js this.removeDataKeys('a', 'b'); ``` --- # Matreshka.Object#setData **Method** ```js Matreshka.Object#setData(key, value, [eventOptions]) → matreshkaObject ``` Sets a property and adds property name to a list of property names which are responsible for data Synonym: `Matreshka.Object#jset` 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`](https://matreshka.js.org/#Matreshka.Object-each), [`Matreshka.Object#keys`](https://matreshka.js.org/#Matreshka.Object-keys), [`Matreshka.Object#toJSON`](https://matreshka.js.org/#Matreshka.Object-toJSON) and other methods. > When ``replaceData`` flag is set as ``true`` then all other properties will be removed from the list of data properties. Apart from that, the method works the same as [`Matreshka#set`](https://matreshka.js.org/#Matreshka-set). **Returns:** [`matreshkaObject`](https://matreshka.js.org/#type-matreshka-object) – self **Fires:** `change`, `change:KEY`, `modify`, `set` ## Arguments | Name | Type | Details | | --- | --- | --- | | `key` | [`string`](https://matreshka.js.org/#type-string) | A key | | `value` | [`*`](https://matreshka.js.org/#type-any) | A value | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options | ## Links - [`Matreshka#set`](https://matreshka.js.org/#Matreshka-set) ## Examples ```js this.setData('a', 1).setData('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((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#setData`](https://matreshka.js.org/#Matreshka.Object-setData) method, you can work with a property like with an ordinary one** ```js this.setData('a', 1).setData('b', 2); this.set('a', 3); this.b = 4; ``` **The use of alternative method name ``jset``** ```js this.jset('a', 1); ``` ## Alternative syntax of the Matreshka.Object#setData method that uses a "key-value" object for setting several properties at once ```js Matreshka.Object#setData(keyValuePairs, evtOpts) → matreshkaObject ``` **Returns:** [`matreshkaObject`](https://matreshka.js.org/#type-matreshka-object) – self ### Arguments | Name | Type | Details | | --- | --- | --- | | `keyValuePairs` | [`object`](https://matreshka.js.org/#type-object) | A key-value object | | `evtOpts` | [`eventOptions`](https://matreshka.js.org/#type-event-options) | A event object | ### Examples ```js this.setData({ a: 1, b: 2 }); ``` **If ``replaceData`` event option set as ``true``, then other properties will be removed from a list of data properties** ```js this .addDataKeys(['a', 'b', 'c']) .setData({ a: 1, b: 2 }, { replaceData: true }); console.log(this.keys()); // ['a', 'b'] ``` --- # Matreshka.Object#toJSON **Method** ```js Matreshka.Object#toJSON([recursive=true]) → object ``` Converts an instance and its internal properties into an ordinary object The method works recursively, calling ``toJSON`` for all internal properties which have such method. To cancel this behavior pass ``false`` as the only argument. **Returns:** [`object`](https://matreshka.js.org/#type-object) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `recursive` (optional) | `true` | [`boolean`](https://matreshka.js.org/#type-boolean) | | ## Examples ```js const matreshkaObject = new Matreshka.Object({ a: 1, b: 2, c: new Matreshka.Object({ d: 3, e: 4 }) }); // returns {a: 1, b: 2, c: { d: 3, e: 4 }} console.log(matreshkaObject.toJSON()); // returns {a: 1, b: 2, c: MatreshkaObject} console.log(matreshkaObject.toJSON(false)); ``` --- # Matreshka.Object#entries **Method** ```js Matreshka.Object#entries() → array ``` Returns an array of ``[key, value]`` pairs of properties which are responsible for data **Returns:** [`array`](https://matreshka.js.org/#type-array) – entries ## Examples ```js for(const [key, value] of this.entries()) { console.log(key, value); } ``` --- # Matreshka.Object#values **Method** ```js Matreshka.Object#values() → array ``` Returns an array of property values which are responsible for data **Returns:** [`array`](https://matreshka.js.org/#type-array) – values ## Examples ```js const values = this.values(); ``` --- # Matreshka.Object#isMatreshkaObject **Property** ```js Matreshka.Object#isMatreshkaObject: boolean ``` The ``isMatreshkaObject`` property always equals ``true`` for instances of [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) class ## Examples ```js console.log(object.isMatreshkaObject); ``` --- # Matreshka.Array **Class** · extends `Matreshka` **Import:** ```js import { MatreshkaArray } from 'matreshka'; ``` The ``Matreshka.Array`` serves as collection class in Matreshka framework. It is inherited from the [`Matreshka`](https://matreshka.js.org/#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. For the reason that methods work the same as original ones (with a few exceptions), they are not presented in this documentation separately but they are gathered in the [`Matreshka.Array#METHOD`](https://matreshka.js.org/#Matreshka.Array-METHOD) section. ```js 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_`](https://matreshka.js.org/#Matreshka.Array-METHOD_). ```js this.push_(1, 2, 3, { silent: true }); this.pop_({ foo: 'bar' }); ``` #### 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 ``shift`` method, the ``shift`` event is fired, calling the ``sort`` method, the ``sort`` event is fired, and so on. ```js this.on('push', evt => { console.log('push is called'); }); this.push(1, 2, 3); ``` __While adding items, ``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 fired 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 as ``added`` property and on the ``addone`` triggering, each particular added item is passed to it as ``addedItem`` property. ```js this.on('add', evt => { console.log(evt.added); // [1,2,3] }); this.push(1, 2, 3); ``` ```js // the handler will be called three times, // as three new item have been added to the array this.on('addone', evt => { console.log(evt.addedItem); // 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 (removed items are contained in the ``removed`` property) and the ``removeone`` event triggers for each removed item individually (removed item is contained in the ``removedItem`` property). ```js this.push(1, 2, 3, 4, 5); this.on('remove', evt => { console.log(evt.removed); // [2, 3, 4] }); this.splice(1, 3); ``` ```js this.push(1, 2, 3, 4, 5); // the handler will be called three times, // as three items have been removed from the array this.on('removeone', evt => { console.log(evt.removedItem); // 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). ```js this.on('modify', evt => { console.log(evt.added); console.log(evt.removed); }); ``` __``length`` is an ordinary property which can be bound to HTML node__ or you can listen changes using the ``change:length`` event name. > 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`](https://matreshka.js.org/#Matreshka.Array-Model) property specifies a class of items that an array contains. It is recommended to inherit ``Model`` from the [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) class or the [`Matreshka.Array`](https://matreshka.js.org/#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 recursively by using the [`Matreshka.Array#toJSON`](https://matreshka.js.org/#Matreshka.Array-toJSON) method. #### Automatic rendering ``Matreshka.Array`` can render HTML nodes on a page automatically in any modifications of an array. The [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#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. For detailed information read the documentation of [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer). ## Links - [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer) - [`Matreshka.Array#Model`](https://matreshka.js.org/#Matreshka.Array-Model) ## Examples **An instance creation** ```js new Matreshka.Array(); ``` **An instance creation with length specifying** ```js new Matreshka.Array(42); ``` Like the native ``Array``, a single number that is not a valid length (negative, fractional or ``NaN``) throws a ``RangeError``. **Items passing on creation** ```js new Matreshka.Array('Hi', {a: 'b'}); ``` **The inheritance** ```js class MyClass extends Matreshka.Array { constructor(items) { super(...items).sayHello(); } sayHello() { alert("Hello World!"); } } ``` **The inheritance using [`Matreshka.Class`](https://matreshka.js.org/#Matreshka.Class) function** ```js const MyClass = Matreshka.Class({ extends: Matreshka.Array, constructor(items) { this.recreate(items).sayHello(); }, sayHello() { alert("Hello World!"); } }); ``` ## Methods and properties - [`METHOD`](https://matreshka.js.org/#Matreshka.Array-METHOD) – Any method from ``Array.prototype`` - [`METHOD_`](https://matreshka.js.org/#Matreshka.Array-METHOD_) – Any method from ``Array.prototype`` with the possibility of passing event object - [`Model`](https://matreshka.js.org/#Matreshka.Array-Model) – The property defines a class of items which will be inserted to a collection - [`isMatreshkaArray`](https://matreshka.js.org/#Matreshka.Array-isMatreshkaArray) – The ``isMatreshkaArray`` property always equals ``true`` for instances of [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) class - [`itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer) – HTML string, a selector or a function which is responsible for rendering DOM nodes of an array on a page - [`mediateItem`](https://matreshka.js.org/#Matreshka.Array-mediateItem) – Transforms an item value - [`onItemRender`](https://matreshka.js.org/#Matreshka.Array-onItemRender) – A function which is called before ``"render"`` event - [`orderBy`](https://matreshka.js.org/#Matreshka.Array-orderBy) – Sorts by properties of array items - [`pull`](https://matreshka.js.org/#Matreshka.Array-pull) – Removes an item with specified index from an array or an item itself - [`recreate`](https://matreshka.js.org/#Matreshka.Array-recreate) – Recreates the [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance - [`renderIfPossible`](https://matreshka.js.org/#Matreshka.Array-renderIfPossible) – The ``renderIfPossible`` property cancels the array rendering if it equals ``false`` - [`rerender`](https://matreshka.js.org/#Matreshka.Array-rerender) – Rerenders DOM nodes of items which are included into an instance - [`restore`](https://matreshka.js.org/#Matreshka.Array-restore) – Restores [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance from existing HTML nodes on a page. - [`toJSON`](https://matreshka.js.org/#Matreshka.Array-toJSON) – Converts [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance into native array - [`trackBy`](https://matreshka.js.org/#Matreshka.Array-trackBy) – ``trackBy`` property indicates a key of unique IDs for collection items - [`from`](https://matreshka.js.org/#Matreshka.Array.from) – The function creates a new [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance from array-like or iterable object - [`of`](https://matreshka.js.org/#Matreshka.Array.of) – The function creates a new [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance with a variable number of arguments, regardless of number or type of the arguments --- # Matreshka.Array#mediateItem **Method** ```js Matreshka.Array#mediateItem(mediator) ``` Transforms an item value This method is used to transform ``Matreshka.Array`` items. Note that calling of this method overrides the [`Matreshka.Array#Model`](https://matreshka.js.org/#Matreshka.Array-Model) property. Calling the method converts the items the array already has and replaces their rendered nodes; no events are fired. ## Arguments | Name | Type | Details | | --- | --- | --- | | `mediator` | [`function`](https://matreshka.js.org/#type-function) | A function which should return transformed value of an item | ## Links - [`Matreshka.Array#Model`](https://matreshka.js.org/#Matreshka.Array-Model) - [`Matreshka#mediate`](https://matreshka.js.org/#Matreshka-mediate) ## Examples ```js // all the array items are integers this.mediateItem(item => parseInt(item) || 0); ``` ```js this.push(1, 2, 3, 4, 5); // all the array items are strings this.mediateItem(String); this.push(6, 7); this.unshift(true, {}); // ["true", "[object Object]", "1", "2", "3", "4", "5", "6", "7"] console.log(matreshkaArray.toJSON()); ``` ```js this.mediateItem(item => { if(item.something) { return new FirstModel(item); } else { return new SecondModel(item); } }); ``` --- # Matreshka.Array#METHOD **Method** ```js Matreshka.Array#METHOD() ``` Any method from ``Array.prototype`` [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) includes all the methods existing in the native JavaScript Array: - [join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) - [pop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) - [push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) - [reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) - [shift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) - [unshift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) - [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) - [splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) - [sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) - [filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) - [forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) - [some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) - [every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) - [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) - [indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) - [lastIndexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf) - [reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) - [reduceRight](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight) - [copyWithin](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/copyWithin) - [find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) - [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) - [fill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) - [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) - [entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) - [keys](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) - [concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) 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 should return a new array (``splice``, ``slice``, ``filter``, ``map``...) return a new ``Matreshka.Array`` instance. - The ``keys``, ``values`` and ``entries`` methods return an array instead of an iterator. - ``fill`` reports the replaced items as ``removed`` in the ``remove`` and ``modify`` events, and ``added`` holds one item per filled index. - ``fill`` and ``copyWithin`` throw an error on a rendered array (one that has a ``container`` or a ``sandbox``). Moreover, the methods generate events which are fired on any array modification. For more detailed information look at [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array). ## Links - [`Matreshka.Array#METHOD_`](https://matreshka.js.org/#Matreshka.Array-METHOD_) ## Examples ```js this.push(1, 2, 3); ``` ```js const matreshkaArray = this .forEach((value, index) => { //... }) .map((value, index) => { //... }); console.log(matreshkaArray.isMatreshkaArray); // true ``` ```js this.reverse(); ``` --- # Matreshka.Array#METHOD_ **Method** ```js Matreshka.Array#METHOD_() ``` Any method from ``Array.prototype`` with the possibility of passing event object Having found out more about [`Matreshka.Array#METHOD`](https://matreshka.js.org/#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`` - disables event triggering - ``dontRender`` - disables [rendering](https://matreshka.js.org/#Matreshka.Array-itemRenderer) - ``skipItemMediator`` - disables [mediators](https://matreshka.js.org/#Matreshka.Array-mediateItem) and [models](https://matreshka.js.org/#Matreshka.Array-Model) ## Links - [`Matreshka.Array#METHOD`](https://matreshka.js.org/#Matreshka.Array-METHOD) ## Examples ```js this.push_(1, 2, 3, { silent: true }); this.pop_({ silent: true }); ``` ```js this.on('modify', evt => { alert(evt.flag); // 42 }); this.push_(1, 2, 3, { flag: 42 }); ``` --- # Matreshka.Array#Model **Method** · Defined by you ```js Matreshka.Array#Model(data, matreshkaArray, index) ``` 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. It is recommended to inherit ``Model`` from the [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) or [`Matreshka.Array`](https://matreshka.js.org/#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 [`Matreshka.Array#toJSON`](https://matreshka.js.org/#Matreshka.Array-toJSON) method. Use [`Matreshka.Array#mediateItem`](https://matreshka.js.org/#Matreshka.Array-mediateItem) for more flexible control of an item class (for example, if you need to use one class for certain items and another one - for others). ``Model`` can be declared as a class field (``Model = MyModel;``) as well as a getter. Class fields are set after ``super(...)`` returns, so the items passed to ``super(...)`` are converted when a method next changes the array; a ``get Model()`` getter converts them right away. Changing ``Model`` later converts the items the array already has and replaces their rendered nodes. ## Arguments | Name | Type | Details | | --- | --- | --- | | `data` | [`object`](https://matreshka.js.org/#type-object) | Data which have been passed to a constructor | | `matreshkaArray` | [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) | An array where an item has been added to | | `index` | [`number`](https://matreshka.js.org/#type-number) | Current index of an instance in the parent array | ## Links - [`Matreshka.Array#mediateItem`](https://matreshka.js.org/#Matreshka.Array-mediateItem) - [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer) ## Examples ```js // define a model class MyModel extends Matreshka.Object { constructor(data, parentArray, index) { super(data); this.doSomething(); } doSomething() { ... } } // define collection class class MyArray extends Matreshka.Array { get Model() { return MyModel; } } const myArray = new MyArray(); // add two items myArray.push({ a: 1, b: 2 }, { a: 3, b: 4 }); console.log(myArray[0] instanceof MyModel); // true console.log(myArray[1] instanceof MyModel); // true // returns [{ a: 1, b: 2 }, { a: 3, b: 4 }] myArray.toJSON(); ``` --- # Matreshka.Array#onItemRender **Method** · Defined by you ```js Matreshka.Array#onItemRender(item, renderEvent) ``` A function which is called before ``"render"`` event The virtual method can be used instead of ``"render"`` event handler. At the same time ``onRender`` method is called in a rendered item with the only argument - an event object. ## Arguments | Name | Type | Details | | --- | --- | --- | | `item` | [`object`](https://matreshka.js.org/#type-object) | A rendered node of a collection | | `renderEvent` | [`object`](https://matreshka.js.org/#type-object) | ``"render"`` event object | ## Examples ```js class MyModel extends Matreshka.Object { constructor(data) { super(data); } onRender(renderEvt) { this.bindNode('isChecked', ':sandbox .my-checkbox'); this.bindNode('text', ':sandbox .text', Matreshka.binders.html()); } } class MyArray extends Matreshka.Array { get Model() { return MyModel; } itemRenderer() { return '
  • ' } constructor() { super().bindNode('sandbox', '.my-form'); } onItemRender(item, renderEvt) { // ... } } const app = new MyArray(); ``` --- # Matreshka.Array#orderBy **Method** ```js Matreshka.Array#orderBy(keys, [orders=asc]) → matreshkaArray ``` Sorts by properties of array items This method works almost like [orderBy from lodash](https://lodash.com/docs#orderBy). It accepts a key or a list of keys as the first arg and an order (asc/desc) or a list of orders as the second arg. **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) – self **Fires:** `sort` ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `keys` | | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | A key or a list of keys | | `orders` (optional) | `asc` | [`string`](https://matreshka.js.org/#type-string) \| [`array`](https://matreshka.js.org/#type-array) | An order or a list of orders corresponding to the list of keys | ## Examples **A little example taken from lodash documentation** ```js 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}] ``` --- # Matreshka.Array#pull **Method** ```js Matreshka.Array#pull(indexOrValue, [eventOptions]) → *|null ``` Removes an item with specified index from an array or an item itself **Returns:** [`*`](https://matreshka.js.org/#type-any) \| [`null`](https://matreshka.js.org/#type-null) – A deletee or ``null`` **Fires:** `pull`, `remove`, `removeone`, `modify` ## Arguments | Name | Type | Details | | --- | --- | --- | | `indexOrValue` | [`object`](https://matreshka.js.org/#type-object) \| [`number`](https://matreshka.js.org/#type-number) | An item index (a number) which has to be removed or the deletee itself (an object) | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event object in case if it is needed to pass some data to event handlers or to set some service flags (eg. ``silent``) | ## Examples **Passing of an index** ```js let removed; this.recreate(['a', 'b', 'c']); removed = this.pull(1); console.log(removed); // 'b' console.log(this.join(',')); // 'a,c' ``` **Passing of a deletee object** ```js const object1 = {}; const object2 = {}; const object3 = {}; let removed; this.push(object1, object2, object3); removed = this.pull(object2); console.log(removed === object2); // true console.log(this.length); // 2 ``` --- # Matreshka.Array#recreate **Method** ```js Matreshka.Array#recreate([array], [eventOptions]) → matreshkaArray ``` Recreates the [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance The method allows to convert any array or array-like into the [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance. If nothing has been passed as the first argument, the instance is cleansed. **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) – self **Fires:** `recreate`, `modify`, `add`, `addone`, `remove`, `removeone` ## Arguments | Name | Type | Details | | --- | --- | --- | | `array` (optional) | [`array`](https://matreshka.js.org/#type-array) | An array or array-like object | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event object | ## Links - [`Matreshka.Array#trackBy`](https://matreshka.js.org/#Matreshka.Array-trackBy) ## Examples ```js // cleanse the array and add 5 new items this.recreate([1, 2, 3, 4, 5]); // cleanse the array this.recreate(); ``` --- # Matreshka.Array#restore **Method** ```js Matreshka.Array#restore([selector], [eventOptions]) → matreshkaArray ``` Restores [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance from existing HTML nodes on a page. In case if a collection is pre-rendered on the page (e. g. via webserver), the method can restore the collection from existing HTML nodes. ```html ``` ```js class MyModel extends Matreshka.Object { constructor(data) { super(data); this.addDataKeys('value'); } onRender() { this.bindNode('value', ':sandbox', Matreshka.binders.html()) } } class MyCollection extends Matreshka.Array { get itemRenderer() { return ':sandbox .renderer'; } constructor() { super() .bindNode('sandbox', '.collection-node') .restore(':sandbox li'); } } const 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](https://matreshka.js.org/#Matreshka.Array-onItemRender)) for every newly added item similar to [usual rendering](https://matreshka.js.org/#Matreshka.Array-itemRenderer). **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) – self **Fires:** `recreate`, `modify`, `add`, `addone` ## Arguments | Name | Type | Details | | --- | --- | --- | | `selector` (optional) | `selector` | A selector | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options | --- # Matreshka.Array#toJSON **Method** ```js Matreshka.Array#toJSON([recursive=true]) → array ``` Converts [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance into native array The method works recursively, calling ``toJSON`` for all items which have such method. To cancel this behavior pass ``false`` as the only argument. **Returns:** [`array`](https://matreshka.js.org/#type-array) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `recursive` (optional) | `true` | [`boolean`](https://matreshka.js.org/#type-boolean) | | ## Examples ```js const matreshkaArray = new Matreshka.Array(1, 2, new MatreshkaArray(3, 4)); // returns [1, 2, [3, 4]] console.log(matreshkaArray.toJSON()); // returns [1, 2, MatreshkaArray] console.log(matreshkaArray.toJSON(false)); ``` --- # Matreshka.Array#rerender **Method** ```js Matreshka.Array#rerender([eventOptions]) → matreshkaArray ``` 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 container 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. To force items rerender (e. g. you use custom template engine) pass a property ``forceRerender`` with ``true`` value to an event object. **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) – self ## Arguments | Name | Type | Details | | --- | --- | --- | | `eventOptions` (optional) | [`eventOptions`](https://matreshka.js.org/#type-event-options) | An event options | ## Examples ```js this.rerender({ forceRerender: true }); ``` --- # Matreshka.Array#itemRenderer **Property** · Defined by you ```js Matreshka.Array#itemRenderer: string|function ``` HTML string, a selector or a function which is responsible for rendering DOM nodes of an array on a page The ``itemRenderer`` overridable property 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`](https://matreshka.js.org/#Matreshka-bindNode)) (this behavior can be canceled, read below) for inserted item and it is inserted into HTML container which is defined in an array. > For brevity, the "class fields" syntax will be used in examples at this article. > ``itemRenderer`` and ``Model`` work as class fields as well as getters; assigning a new value to an ``itemRenderer`` class field rerenders the items. See [`Matreshka.Array#Model`](https://matreshka.js.org/#Matreshka.Array-Model) about the items passed to ``super(...)``. #### Where is created node inserted? In order to define a place 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`](https://matreshka.js.org/#Matreshka-bindNode). Rendering to a sandbox: ```html ``` ```js class MyArray extends Matreshka.Array { itemRenderer = '
  • '; get Model() { return MyModel; } constructor() { // sandbox definition super().bindNode('sandbox', '.my-list'); } } ``` Now all newly created ``
  • `` 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 and it includes other HTML nodes. ```html

    This is my awesome list

    ``` ```js class MyArray extends Matreshka.Array { itemRenderer = '
  • '; get Model() { return MyModel; } constructor() { super(); // sandbox definition this.bindNode('sandbox', '.my-widget'); // a definition of 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 a property value ```js class MyArray extends Matreshka.Array { get Model() { return MyModel; } itemRenderer = '
    foo
    '; constructor() { ... } } ``` #### A selector as a property value In case if you carry over the templates for the items to the HTML page, ``itemRenderer`` supports the selector as a value. When this occurs, [`Matreshka.Array`](https://matreshka.js.org/#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, an exception will be thrown. > HTML string is different from a selector due to the presence of the ``<`` symbol in a string. ```html ``` ```js class MyArray extends Matreshka.Array { get Model() { return MyModel; } itemRenderer = '#my-template'; constructor() { ... } } ``` #### A function as a 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__ ```js class MyArray extends Matreshka.Array { itemRenderer() { return '
    foo
    '; } } ``` __A selector__ ```js class MyArray extends Matreshka.Array { itemRenderer() { return '#my-template'; } } ``` __DOM node__ ```js class MyArray extends Matreshka.Array { itemRenderer() { return document.createElement('div'); } } ``` #### Parent renderer overlapping by the ``render`` property Sometimes it is convenient to declare a renderer inside a [model](https://matreshka.js.org/#Matreshka.Array-Model) class. The ``renderer`` property overlaps the ``itemRenderer`` value if it is specified for a child item of a collection. ```js class MyModel extends Matreshka.Object { renderer = '
    foo
    '; } class MyArray extends Matreshka.Array { Model = MyModel; itemRenderer = 'bar'; constructor() { ... } } ``` 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. #### ``render`` and ``afterrender`` events After an item has been inserted into an array and its HTML node has already been created but it hasn't been inserted into array container yet, the ``render`` event is fired on inserted item. After its triggering you can declare needed data bindings. ``afterrender`` is fired when HTML node is inserted into the container. ```html
    ``` ```js class MyModel extends Matreshka.Object { constructor(data) { super(data); // wait for the event triggering this.on('render', () => { // define bindings this.bindNode('isChecked', ':sandbox .my-checkbox'); this.bindNode('text', ':sandbox .text', Matreshka.binders.html()); }); } } class MyArray extends Matreshka.Array { get Model() { return MyModel; } itemRenderer = ``; constructor() { super(); this.bindNode('sandbox', '.my-form'); this.push({ isChecked: true, text: 'Buy a raccoon' }, { isChecked: false, text: 'Sell the raccoon' }); } } const app = new MyArray(); ``` The code above will create the following HTML tree: ```html
    ``` And it will bind the checkboxes to the corresponding ``isChecked`` and ``text`` properties. Remember, the opportunity of listening delegated events is implemented in the framework. The array can listen to an event of an item rendering, using the ``*@render`` event name (see the documentation of [`eventNames`](https://matreshka.js.org/#type-event-names)). ```js this.on('*@render', () => { 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`` property to ``false`` for an item to cancel this behavior. ```js class MyModel extends Matreshka.Object { bindRenderedAsSandbox = false; // ... } ``` #### ``onItemRender`` and ``onRender`` To improve the readability of code there is a virtual method called [`Matreshka.Array#onItemRender`](https://matreshka.js.org/#Matreshka.Array-onItemRender), which can be used instead of ``render`` event. As second alternative, the ``onRender`` can be used for a "model". ```js class MyModel extends Matreshka.Object { constructor(data) { super(data); } onRender(evt) { this.bindNode('isChecked', ':sandbox .my-checkbox'); this.bindNode('text', ':sandbox .text', Matreshka.binders.html()); } } class MyArray extends Matreshka.Array { get Model() { return MyModel; } itemRenderer = '...'; constructor() { super(); //... } onItemRender(item, evt) { //... } } const app = new MyArray(); ``` #### A template engine If you have a look at the examples of using [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) and [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#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. 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. A template including bindings (see [`Matreshka#parseBindings`](https://matreshka.js.org/#Matreshka-parseBindings)) can be passed to ``itemRenderer`` for that. ```js class MyArray extends Matreshka.Array { itemRenderer = ``; // ... } const app = new MyArray(); ``` #### 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, set a property ``renderIfPossible`` of ``Matreshka.Array`` instance as ``false``. ```js class MyArray extends Matreshka.Array { renderIfPossible = false; // ... } ``` #### Moving an object across few collections By default, when you add an object to an array the framework will try to render it using ``itemRenderer``. 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 while adding the new item to another array. ```js this.push_(item, { moveSandbox: true }) ``` #### ``itemRenderer`` reassigning When you reassign ``itemRenderer`` a collection rerenders automatically. ```js this.itemRenderer = '
    '; ``` This ability allows to load renderer from a server. ```js 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`](https://matreshka.js.org/#Matreshka-set) with ``forceRerender`` flag set to ``false``. ```js this.set('itemRenderer', renderer, { forceRerender: false }); ``` It's useful when you use server prerendering (look at the [`Matreshka.Array#restore`](https://matreshka.js.org/#Matreshka.Array-restore)) and template needs to be loaded asynchronously. ```js class MyArray extends Matreshka.Array { constructor() { super() .bindNode('sandbox', '.some-node') .restore(); fetch('templates/template.html') .then(resp => resp.text()) .then(data => { this.set('itemRenderer', data, { forceRerender: false }); }); } } ``` #### Rendering of a collection that contains any kind of object It's not obligatory to fill an array with only ``Matreshka`` instances, you can render any kind of object. Bindings for such objects can be defined using static method [`Matreshka.bindNode`](https://matreshka.js.org/#Matreshka.bindNode). ```js class MyArray extends Matreshka.Array { // Model is not given itemRenderer = ...; onItemRender(item) { Matreshka.bindNode(item, 'x', ':sandbox .some-node'); } } ``` One more little example: the rendering of a simple list: ```js class MyArray extends Matreshka.Array { itemRenderer = '
  • {{value}}
  • '; constructor() { super().bindNode('sandbox', '.my-list'); } } const arr = new MyArray(); arr.push({ value: 'Item 1' }, { value: 'Item 2' }); ``` ## Arguments | Name | Type | Details | | --- | --- | --- | | `item` | [`object`](https://matreshka.js.org/#type-object) | An object, which will be rendered (in case you need to use some conditions) | ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) - [`Matreshka.Array#Model`](https://matreshka.js.org/#Matreshka.Array-Model) --- # Matreshka.Array#trackBy **Property** · Defined by you ```js Matreshka.Array#trackBy: string ``` ``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`](https://matreshka.js.org/#Matreshka.Array-Model)) will not be created and new DOM node will not be rendered. ``trackBy`` works only using [`Matreshka.Array#recreate`](https://matreshka.js.org/#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). ```js class MyArray extends Matreshka.Array { get trackBy() { return '_id'; } constructor() { super(); //... } } const 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. ```js class MyArray extends Matreshka.Array { get trackBy() { return '$index'; } constructor() { super(); //... } } const 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 - [`Matreshka.Array#recreate`](https://matreshka.js.org/#Matreshka.Array-recreate) --- # Matreshka.Array#isMatreshkaArray **Property** ```js Matreshka.Array#isMatreshkaArray: boolean ``` The ``isMatreshkaArray`` property always equals ``true`` for instances of [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) class ## Examples ```js console.log(object.isMatreshkaArray); ``` --- # Matreshka.Array#renderIfPossible **Property** ```js Matreshka.Array#renderIfPossible: boolean ``` The ``renderIfPossible`` property cancels the array rendering if it equals ``false`` ## Links - [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer) ## Examples ```js class MyArray extends Matreshka.Array { get renderIfPossible() { return false; } // ... } ``` --- # Matreshka.Array.from **Method** ```js Matreshka.Array.from(arrayLike, [mapFn], [thisArg]) → matreshkaArray ``` The function creates a new [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance from array-like or iterable object **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) ## Arguments | Name | Type | Details | | --- | --- | --- | | `arrayLike` | [`object`](https://matreshka.js.org/#type-object) | Array-like or iterable object | | `mapFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | The mapping function which is called for each element of an array | | `thisArg` (optional) | [`*`](https://matreshka.js.org/#type-any) | An object which is used as ``this`` on calling ``mapFn`` | ## Links - [Array.from](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/from) ## Examples ```js const matreshkaArray = Matreshka.Array.from([1, 2, 3, 4]); ``` ```js const matreshkaArray = Matreshka.Array.from([1, 2, 3, 4], item => item * 2); ``` **Inheritance of the method** ```js class MyClass extends Matreshka.Array { // ... } const myArray = MyClass.from([1, 2, 3, 4]); console.log(myArray instanceof MyClass); // true ``` --- # Matreshka.Array.of **Method** ```js Matreshka.Array.of() → matreshkaArray ``` The function creates a new [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance with a variable number of arguments, regardless of number or type of the arguments **Returns:** [`matreshkaArray`](https://matreshka.js.org/#type-matreshka-array) ## Links - [Array.of](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/of) ## Examples ```js const matreshkaArray = Matreshka.Array.of(1, 2, 3, 4); ``` **Inheritance of the method** ```js class MyClass extends Matreshka.Array { // ... } const myArray = MyClass.of(1, 2, 3, 4); console.log(myArray instanceof MyClass); // true ``` --- # Matreshka.binders **Namespace** **Import:** ```js import { binders } from 'matreshka'; ``` A namespace for binders. Out of the box it contains general-purpose binders and 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`` namespace must be made as a function which returns a binder (such functions usually called "binder creators"). > At this documentation the properties from ``Matreshka.binders`` are used directly. But to make your code more readable it's recommended to assign them to a variable. ```js const html = Matreshka.binders.html; // ... this.bindNode('x', node, html()); ``` Or import them as CJS/ES2015 module: ```js // import few binders per once import { binders } from 'matreshka'; const { html, text, prop } = binders; ``` The binders ship with the ``matreshka`` package. ## Links - [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) - [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) ## Examples ```js Matreshka.binders.myCoolBinder = (var1, var2) => { return { on: 'click', getValue() { ... }, setValue() { ... }, initialize() { ... }, destroy() { ... } }; }; this.bindNode('myKey', '.my-element', Matreshka.binders.myCoolBinder('Hello', 'World')); ``` ## Binders - [`attr`](https://matreshka.js.org/#Matreshka.binders.attr) – Returns a binder which changes an attribute of DOM node depending on an object property value - [`className`](https://matreshka.js.org/#Matreshka.binders.className) – Returns a binder which switches over DOM node class name depending on an object property value. If property value equals ``true`` non-strictly, a class name is added, otherwise - it's removed. The logic can be changed by passing ``false`` as the second argument and in this way, a class name will be added when a property value equals ``false`` non-strictly and vice versa. - [`dataset`](https://matreshka.js.org/#Matreshka.binders.dataset) – Returns a binder which changes given [dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) property of bound DOM node depending on an object property value. - [`display`](https://matreshka.js.org/#Matreshka.binders.display) – Returns a binder which controls a visibility of DOM node (using ``style.display``) depending on an object property value - [`existence`](https://matreshka.js.org/#Matreshka.binders.existence) – Returns a binder which controls an existence of DOM node at DOM tree depending on an object property value - [`html`](https://matreshka.js.org/#Matreshka.binders.html) – Returns a binder which changes ``innerHTML`` of bound DOM node depending on an object property value - [`input`](https://matreshka.js.org/#Matreshka.binders.input) – Returns a binder which binds an object property to an ``input`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. - [`output`](https://matreshka.js.org/#Matreshka.binders.output) – Returns a binder which binds an object property to an ``output`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. - [`progress`](https://matreshka.js.org/#Matreshka.binders.progress) – Returns a binder which binds an object property to a ``progress`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. - [`prop`](https://matreshka.js.org/#Matreshka.binders.prop) – Returns a binder which changes given property of DOM node depending on an object property value - [`select`](https://matreshka.js.org/#Matreshka.binders.select) – Returns a binder which binds an object property to a ``select`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. - [`style`](https://matreshka.js.org/#Matreshka.binders.style) – Returns a binder which changes given style property of bound DOM node depending on an object property value - [`text`](https://matreshka.js.org/#Matreshka.binders.text) – Returns a binder which changes ``textContent`` of bound DOM node depending on an object property value - [`textarea`](https://matreshka.js.org/#Matreshka.binders.textarea) – Returns a binder which binds an object property to a ``textarea`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. --- # Matreshka.binders.attr **Method** **Import:** ```js import { binders } from 'matreshka'; const { attr } = binders; ``` ```js Matreshka.binders.attr(attribute, [mappingFn]) → binder ``` Returns a binder which changes an attribute of DOM node depending on an object property value The value can be transformed using ``mappingFn`` argument. ``undefined`` and ``null`` set an empty attribute; the attribute is not removed. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `attribute` | [`string`](https://matreshka.js.org/#type-string) | Attribute name | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('image', 'img.my-image', Matreshka.binders.attr('src')); this.image = 'http://example.com/cats.jpg'; ``` **The usage of mapping function** ```js this.bindNode('myKey', '.my-node', Matreshka.binders.attr('foo', value => `Hello, ${value}`)); this.myKey = 'World'; // the foo attr now has value "Hello, World" ``` --- # Matreshka.binders.className **Method** **Import:** ```js import { binders } from 'matreshka'; const { className } = binders; ``` ```js Matreshka.binders.className(className, [bool=true]) → binder ``` Returns a binder which switches over DOM node class name depending on an object property value. If property value equals ``true`` non-strictly, a class name is added, otherwise - it's removed. The logic can be changed by passing ``false`` as the second argument and in this way, a class name will be added when a property value equals ``false`` non-strictly and vice versa. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `className` | | [`string`](https://matreshka.js.org/#type-string) | | | `bool` (optional) | `true` | [`boolean`](https://matreshka.js.org/#type-boolean) | | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.className('foo')); this.myKey = true; // adds the 'foo' class this.myKey = false; // removes the 'foo' class ``` ```js this.bindNode('myKey', '.my-element', Matreshka.binders.className('foo', false)); this.myKey = false; // adds the 'foo' class this.myKey = true; // removes the 'foo' class ``` --- # Matreshka.binders.dataset **Method** **Import:** ```js import { binders } from 'matreshka'; const { dataset } = binders; ``` ```js Matreshka.binders.dataset(property, [mappingFn]) → binder ``` Returns a binder which changes given [dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset) property of bound DOM node depending on an object property value. The property value can be transformed using ``mappingFn`` argument. ``undefined`` and ``null`` show as an empty string. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `property` | [`string`](https://matreshka.js.org/#type-string) | A property of ``dataset`` object | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.dataset('myProp')); this.myKey = 'foo'; ``` **The usage of mapping function** ```js this.bindNode('myKey', '.my-element', Matreshka.binders.dataset('myProp', value => `Hello, ${value}`)); this.myKey = 'foo'; // the attr data-my-prop now has value "Hello, foo" ``` --- # Matreshka.binders.display **Method** **Import:** ```js import { binders } from 'matreshka'; const { display } = binders; ``` ```js Matreshka.binders.display([bool=true]) → binder ``` Returns a binder which controls a visibility of DOM node (using ``style.display``) depending on an object property value **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `bool` (optional) | `true` | [`boolean`](https://matreshka.js.org/#type-boolean) | If the argument equals ``true``, a node is hidden when a property value is falsy; if it equals ``false``, it is hidden when a property value is truly. | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.display(true)); ``` ```js this.bindNode('myKey', '.my-element', Matreshka.binders.display(false)); ``` --- # Matreshka.binders.existence **Method** **Import:** ```js import { binders } from 'matreshka'; const { existence } = binders; ``` ```js Matreshka.binders.existence([bool=true]) → binder ``` Returns a binder which controls an existence of DOM node at DOM tree depending on an object property value The binder works the same way as [`Matreshka.binders.display`](https://matreshka.js.org/#Matreshka.binders.display), but instead of visibility change the existence at page DOM is changed. The binder is useful for: - Big appications: show one or another page depending on route state; - For infinite scrolling; - For other cases where you need to hide an element but its existence at DOM tree isn't necessary. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `bool` (optional) | `true` | [`boolean`](https://matreshka.js.org/#type-boolean) | If the argument equals ``true``, a node is removed when a property value is falsy; if it equals ``false``, it is removed when a property value is truly | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.existence(true)); ``` ```js this.bindNode('myKey', '.my-element', Matreshka.binders.existence(false)); ``` --- # Matreshka.binders.html **Method** **Import:** ```js import { binders } from 'matreshka'; const { html } = binders; ``` ```js Matreshka.binders.html([mappingFn]) → binder ``` Returns a binder which changes ``innerHTML`` of bound DOM node depending on an object property value The property value can be transformed using ``mappingFn`` argument. ``undefined`` and ``null`` show as an empty string. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.html()); // sets innerHTML="
    foo
    " this.myKey = '
    foo
    '; ``` **The usage of mapping function** ```js this.bindNode('myKey', '.my-element', Matreshka.binders.html(value => `Hello, ${value}`)); // sets innerHTML="Hello,
    foo
    " this.myKey = '
    foo
    '; ``` --- # Matreshka.binders.prop **Method** **Import:** ```js import { binders } from 'matreshka'; const { prop } = binders; ``` ```js Matreshka.binders.prop(property, [mappingFn]) → binder ``` Returns a binder which changes given property of DOM node depending on an object property value The property value can be transformed using ``mappingFn`` argument. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `property` | [`string`](https://matreshka.js.org/#type-string) | A property name | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('disabled', '.my-button', Matreshka.binders.prop('disabled')); // sets disabled = true property for the node this.disabled = true; // sets disabled = false property for the node this.disabled = false; ``` **The usage of mapping function** ```js this.bindNode('myProp', '.my-node', Matreshka.binders.prop('foo', value => `Hello, ${value}`)); // foo property of the element now has value "Hello, World" this.myProp = 'World'; ``` --- # Matreshka.binders.style **Method** **Import:** ```js import { binders } from 'matreshka'; const { style } = binders; ``` ```js Matreshka.binders.style(property, [mappingFn]) → binder ``` Returns a binder which changes given style property of bound DOM node depending on an object property value The property value can be transformed using ``mappingFn`` argument. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `property` | [`string`](https://matreshka.js.org/#type-string) | A property of ``style`` object (camel-cased) | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('myKey', '.my-progres', Matreshka.binders.style('backgroundColor')); this.myKey = 'red'; // background-color of .my-progress is red now ``` **The usage of mapping function** ```js this.bindNode('myKey', '.my-element', Matreshka.binders.style('backgroundImage', value => `url("${value}")`)); this.myKey = 'cats.jpg'; // backgroundImage now equals to "url("cats.jpg")" ``` --- # Matreshka.binders.text **Method** **Import:** ```js import { binders } from 'matreshka'; const { text } = binders; ``` ```js Matreshka.binders.text([mappingFn]) → binder ``` Returns a binder which changes ``textContent`` of bound DOM node depending on an object property value The property value can be transformed using ``mappingFn`` argument. ``undefined`` and ``null`` show as an empty string. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `mappingFn` (optional) | [`function`](https://matreshka.js.org/#type-function) | Mapping function | ## Examples ```js this.bindNode('myKey', '.my-element', Matreshka.binders.text()); this.myKey = 'foo'; // sets textContent as "foo" ``` **The usage of mapping function** ```js this.bindNode('myKey', '.my-element', Matreshka.binders.text(value => `Hello, ${value}`)); this.myKey = 'foo'; // sets textContent as "Hello, foo" ``` --- # Matreshka.binders.input **Method** **Import:** ```js import { binders } from 'matreshka'; const { input } = binders; ``` ```js Matreshka.binders.input([type]) → binder ``` Returns a binder which binds an object property to an ``input`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. For text-like inputs, ``undefined`` and ``null`` show as an empty string. For a ``radio`` input, a checked radio sets the property to its ``value``; an unchecked radio doesn't change the property. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Type | Details | | --- | --- | --- | | `type` (optional) | [`string`](https://matreshka.js.org/#type-string) | Input type | ## Examples ```js this.bindNode('myKey', '.my-input', Matreshka.binders.input('range')); ``` --- # Matreshka.binders.output **Method** **Import:** ```js import { binders } from 'matreshka'; const { output } = binders; ``` ```js Matreshka.binders.output() → binder ``` Returns a binder which binds an object property to an ``output`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. ``undefined`` and ``null`` show as an empty string. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Examples ```js this.bindNode('myKey', '.my-output', Matreshka.binders.output()); ``` --- # Matreshka.binders.progress **Method** **Import:** ```js import { binders } from 'matreshka'; const { progress } = binders; ``` ```js Matreshka.binders.progress() → binder ``` Returns a binder which binds an object property to a ``progress`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Examples ```js this.bindNode('myKey', '.my-progres', Matreshka.binders.progress()); ``` --- # Matreshka.binders.select **Method** **Import:** ```js import { binders } from 'matreshka'; const { select } = binders; ``` ```js Matreshka.binders.select([multiple=false]) → binder ``` Returns a binder which binds an object property to a ``select`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. ``undefined`` and ``null`` select the option without a value, if there is one. With ``multiple`` set to ``true``, the property can be an array of values, a single value or ``null`` (nothing selected); values are compared as strings, so numbers work too. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Arguments | Name | Default | Type | Details | | --- | --- | --- | --- | | `multiple` (optional) | `false` | [`boolean`](https://matreshka.js.org/#type-boolean) | If select is ``multiple`` | ## Examples ```js this.bindNode('myKey', '.my-select', Matreshka.binders.select(true)); ``` --- # Matreshka.binders.textarea **Method** **Import:** ```js import { binders } from 'matreshka'; const { textarea } = binders; ``` ```js Matreshka.binders.textarea() → binder ``` Returns a binder which binds an object property to a ``textarea`` element value. It is not obligatory to use the binder directly because it is included in the [`Matreshka.defaultBinders`](https://matreshka.js.org/#Matreshka.defaultBinders) list. **Returns:** [`binder`](https://matreshka.js.org/#type-binder) ## Examples ```js this.bindNode('myKey', '.my-textarea', Matreshka.binders.textarea()); ``` --- # Matreshka.Router **Class** **Import:** ```js import { Router } from 'matreshka/router'; ``` [`Matreshka.initRouter`](https://matreshka.js.org/#Matreshka.initRouter) is powered by ``Matreshka.Router`` class. It accepts only one argument - router type (``"hash"``, ``"history"`` or a custom string). By default, the library creates two instances of ``Matreshka.Router`` with types ``hash`` and ``history``. They live at ``Matreshka.Router.hash`` and ``Matreshka.Router.history``. The router uses lazy initialization so when you just attach the script onto webpage, the library does nothing. For these two types of instances the singleton pattern is used. That means when you're trying to create another instance of ``hash`` routing via ``new Matreshka.Router('hash')``, the ``Matreshka.Router.hash`` will be returned instead of new instance creation. This logic centralizes URL handling, gives positive effect to the performance and doesn't make potential collisions. Objects which are handled by ``initRouter`` just subscribe to the changes of needed type of the router. Custom instances (non-hash and non-history) of ``Matreshka.Router`` can be created manually in case if you generate URL for further use. At this case changes of target properties don't affect on ``hash`` and don't call ``pushState``. #### Properties ``Matreshka.Router`` instances has 3 properties. - ``path`` - contains actual URL, eg ``/foo/bar/baz/``. - ``hashPath`` - contains actual URL and hashbang as a prefix, eg ``#!/foo/bar/baz/`` - ``parts`` - contains an array of all parts of the path, eg ``['foo', 'bar', 'baz']``. All these properties are created using [`Matreshka#calc`](https://matreshka.js.org/#Matreshka-calc), which means when you change one property, the others are changed automatically. ```js Matreshka.Router.hash.path = '/foo/bar/baz/'; ``` By changing these properties you can trigger needed procedures (update the path, change subscribed objects etc.) #### Methods - ``subscribe(object, route)`` - subscribes object for route changes. - ``init()`` - used for lazy initialization in ``subscribe`` method (no need to call it manually). ## Arguments | Name | Type | Details | | --- | --- | --- | | `type` | [`string`](https://matreshka.js.org/#type-string) | ``"hash"``, ``"history"`` or a custom string | ## Examples ```js const customRouter = new Matreshka.Router('myType'); const object = { a: 'foo', b: 'bar' }; customRouter.subscribe(object, '/a/b/'); console.log(customRouter.path); // /foo/bar/ ``` --- # * **Type** Any type ## Examples ```js let whatever = 'foo'; whatever = 42; ``` --- # $nodes **Type** DOM nodes collection. For example, an array of nodes, a NodeList or a jQuery instance. ## Examples ```js let $nodes = $('.foo'); $nodes = document.querySelectorAll('.bar'); ``` --- # array **Type** An array ## Examples ```js const arr = ['foo', undefined, null, () => {}]; ``` --- # binder **Type** ``binder`` contains all information about how to synchronize instance property value with DOM node state. Every member of a binder uses HTML node as its context (``this``) ## Properties | Name | Type | Details | | --- | --- | --- | | `on` (optional) | [`string`](https://matreshka.js.org/#type-string) \| [`function`](https://matreshka.js.org/#type-function) | DOM event (or space-delimited list of events) which tells when the node state is changed. Besides, it accepts a function as a value if you need to customize a listener definition | | `getValue` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which tells how to retrieve a value (state) from HTML node when DOM event is fired | | `setValue` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which tells how to change DOM node when the property value is changed | | `initialize` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which is called before binding is launched. For example it can initialize jQuery plugin or something else | | `destroy` (optional) | [`function`](https://matreshka.js.org/#type-function) | A function which is called when a binding is removed using ``unbindNode`` method | ## Examples ```js const binder = { on: 'click', getValue(bindingOptions) { return this.value; }, setValue(v, bindingOptions) { this.value = v; }, initialize(bindingOptions) { alert('A binding is initialized'); }, destroy(bindingOptions) { alert('A binding is destroyed'); } }; this.bindNode('a', '.my-checkbox', binder); ``` ```js const binder = { on(callback, bindingOptions) { this.onclick = callback; }, // ... }; // ... ``` --- # boolean **Type** A boolean ## Examples ```js const bool = true; ``` --- # class **Type** A class made using ECMAScript 2015 syntax or returned by [`Matreshka.Class`](https://matreshka.js.org/#Matreshka.Class) function ## Examples ```js class MyClass { method() { ... } }; ``` ```js const MyClass = Matreshka.Class({ method() { ... } }); ``` --- # eventHandler **Type** Event handler. Takes any arguments passed to [`Matreshka#trigger`](https://matreshka.js.org/#Matreshka-trigger) ## Arguments | Name | Type | Details | | --- | --- | --- | | `options` | `...*` | Any arguments | ## Examples ```js const eventHandler = (...args) => { console.log(args); }; this.on('fyeah', eventHandler); // logs 'foo', 'bar', 'baz' this.trigger('fyeah', 'foo', 'bar', 'baz'); ``` --- # eventNames **Type** Event name or space-delimited list of event names. ##### Custom events. ```js this.on('myevent', () => {...}); this.trigger('myevent'); ``` ##### ``change:KEY`` which is triggered every time when a property is changed. ```js this.on('change:x', evt => {...}); this.x = 42; ``` ##### ``beforechange:KEY`` which is triggered every time before a property is changed. ```js this.on('beforechange:x', evt => {...}); this.x = 42; ``` ##### ``addevent:NAME`` and ``addevent`` which are triggered on event add. ```js // for any event this.on('addevent', evt => {...}); // for "someevent" event this.on('addevent:someevent', evt => {...}); // the line below fires "addevent" and "addevent:someevent" this.on('someevent', evt => {...}); ``` ##### ``removeevent:NAME`` and ``removeevent`` which are triggered on event remove. ```js // for any event this.on('removeevent', evt => {...}); // for "someevent" event this.on('removeevent:someevent', evt => {...}); // the line below fires "removeevent" and "removeevent:someevent" this.off('someevent', 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 which is bound to the KEY. ```js this.bindNode('x', '.my-div'); this.on('click::x', 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. ```html
    ``` ```js this.bindNode('x', '.my-div'); this.on('click::x(.my-button)', 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. ```js this.bindNode('sandbox', '.my-div'); this.on('click::(.my-button)', evt => { alert('clicked ".my-button"'); }); ``` The same as: ```js this.bindNode('sandbox', '.my-div'); this.on('click::sandbox(.my-button)', 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. ```js this.on('a@someevent', () => {...}); this.on('a.b.c@change:d', () => {...}); ``` If you need to listen an event of every item of [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) or every data property of [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object), you can use an asterisk "*" instead of specific property name. ```js this.on('*@someevent', () => {...}); this.on('*.b.*.d@change:e', () => {...}); ``` ##### Any combinations. All events described above can be combined. ```js this.on('x.y.z@click::(.my-selector)', () => {...}); ``` --- # eventOptions **Type** An event object An object which can contain service flags or custom data which will be passed to an event handler ## Examples ```js const eventOptions = { silent: true }; this.a = 1; this.on('change:a', () => { alert('a is changed'); }); this.set('a', 2, eventOptions); // no alert ``` ```js const eventOptions = { f: 'yeah' }; this.a = 1; this.on('change:a', eventOptions => { alert(eventOptions.f); }); this.set('a', 2, eventOptions); // alerts "yeah" ``` --- # function **Type** A function ## Examples ```js function comeOnBarbieLetsGoParty() { alert("I'm a Barbie girl, in a Barbie world"); } ``` --- # matreshka **Type** [`Matreshka`](https://matreshka.js.org/#Matreshka) instance ## Examples ```js const matreshka = new Matreshka(); obj.calc('a', 'b'); ``` --- # matreshkaArray **Type** [`Matreshka.Array`](https://matreshka.js.org/#Matreshka.Array) instance ## Examples ```js const arr = new Matreshka.Array(1, 2, 3); arr.push(4); ``` --- # matreshkaObject **Type** [`Matreshka.Object`](https://matreshka.js.org/#Matreshka.Object) instance ## Examples ```js const obj = new Matreshka.Object({ foo: 'x' }); obj.setData({ bar: 'y' }); ``` --- # node **Type** A DOM node ## Examples ```js const node = document.querySelector('.foo'); ``` --- # null **Type** null ## Examples ```js const x = null; ``` --- # number **Type** A number ## Examples ```js const num = 42; ``` --- # object **Type** An object ## Examples ```js const obj = { foo: 'x', ['bar']: 'y' }; ``` --- # string **Type** A string ## Examples ```js const foo = 'bar'; ``` --- # FAQ ## How does Matreshka work? Matreshka uses accessors, setters in particular, for implementing the two-way data binding and catching the events of property changing. As an example of how the two-way data binding works ([bindNode](https://matreshka.js.org/#Matreshka-bindNode) function in particular), have a look at this code: ```js function bindNode(object, key, node, binder) { let value = object[key]; Object.defineProperty(object, key, { get() { return value; }, set(v) { binder.setValue.call(node, v); } }); node.addEventListener(binder.on, () => { value = binder.getValue.call(node); }); } ``` As you see, it’s real easy (for simplicity, the function doesn’t support many-to-many binding). ## How to pre-render an application on a server For the app pre-rendering Matreshka.js can be used on Node.js (``window`` global object can be created via [jsdom](https://github.com/jsdom/jsdom)) or any template system you want on any server platform. The first case is fine for static HTML generation and the second for dynamic pages. The task of client-side is to restore application state from HTML. [`Matreshka#bindNode`](https://matreshka.js.org/#Matreshka-bindNode) extracts element value and assigns it to a property and [`Matreshka.Array#restore`](https://matreshka.js.org/#Matreshka.Array-restore) restores a state of a collection. ## What is "debounce" At this page you often can see the phrase "micropattern debounce". This is widely used pattern which enforces that a function not be called again until a certain amount of time has passed without it being called. More info can be found [there](https://davidwalsh.name/javascript-debounce-function). ## How should look like a big application? An application written with Matreshka.js usually represents one nested JavaScript object where every branch is [`Matreshka`](https://matreshka.js.org/#Matreshka) instance. The new branches are created using [`Matreshka#instantiate`](https://matreshka.js.org/#Matreshka-instantiate) which ensures the integrity of the application and allows to replace a state of the application using ordinary assignment. ## How to render one object at few collections The first thing: you need to set ``bindRenderedAsSandbox`` as ``false`` for an item class. It turns off automatic sandbox initialization for rendered object (two sandboxes for one object aren't allowed). The second thing: when ``render`` event is fired, check where the object is rendered. Parent array can be get using ``parentArray`` property of the event object. Example. You have ``User`` class and two collections ``UsersA`` and ``UsersB`` (their [`Matreshka.Array#itemRenderer`](https://matreshka.js.org/#Matreshka.Array-itemRenderer) can be different). For both collections ``User`` is a [model](https://matreshka.js.org/#Matreshka.Array-Model). ```js class User extends Matreshka.Object { constructor() { super(); this.bindRenderedAsSandbox = false; setInterval(() => { // when "name" is changed // both bound nodes also change this.name = Math.random(); }, 5000); } onRender(evt) { const { parentArray, node } = evt; if(parentArray instanceof UsersA) { this.bindNode({ // pseudo-sandbox creation for syntax sugar at selectors // (not required) nodeA: node, name: ':bound(nodeA) .name', email: ':bound(nodeA) .email', }); } else if(parentArray instanceof UsersB) { this.bindNode({ nodeB: node, name: ':bound(nodeB) .user-name', }); } } } ``` Actually there are many ways to solve this problem. For example bindings can be declared at classes of the collections (an array will listen to ``render`` event of inserted objects)...