(Archive) Matreshka.js v0.1
- Tutorial
The article is out of date. See current version history .
(All previous articles have been updated to the current state)
Repository
Site (there is also documentation)
Hello everyone. 5 months have passed since the last publication of a series of articles about Matryoshka. Since then, a small number of errors have been fixed, several convenient features have appeared, including under the influence of your comments, the project has found a sponsor in the person of Shooju , received a logo and a normal, non-bootstrap website.
This coolest method allows you to establish the dependence of some data on others. The first argument is the key of the dependent property, the second is an array of keys on which the property depends (or a string with keys enumerated by a space), the third is a handler function that should return a new value for the property. This is a kind of replacement for getter, with the difference that the getter is called every time you get a property, and
Say we need a property to
This is what pure event code looks like:
Now compare it with this:
Or even with this:
Firstly , we have to do less body movements (no heap needed
Secondly , by the name of the method and arguments, we clearly understand why the corresponding lines of code are created. Translating into human language, the first method can be voiced as follows: "when changing properties,
Thirdly , if one of the properties on which the other property depends is changed with a flag
For example, there is the task of calculating the perimeter.
Option 1, on events:
Option 2 using dependencies:
Now, if we call:
Please note that if you hung an event handler on a change
In the next version, it is planned to add the dependence of the property on data located in other classes (a common task in applications where data dominates the appearance). This is already implemented, but not documented due to language syntax limitations. It is assumed that the dependence on other classes will look like this:
Where the odd array element from the second argument is an instance, the even one is a list of keys. It looks specific, I will be glad for other options.
On the page with examples, you can see the method live .
Regarding Rendol 's comment : mapping can be implemented using dependencies.
Quite often, the task of validating and converting data is involved. Let's say your class has a property
Do you understand what is going on here? The first handler converts
The mediator (or mediator) changes the value of the property before any event associated with the change of this property is triggered.
Method Syntax
For example, a property
And for those who know Javascript well:
Mediators are not limited to such simple possibilities. Nothing prohibits making any calculations, but only carefully so as not to harm the performance of the application.
The method is mega-convenient and cool, including when the server accepts a certain type of value. There can be only one mediator. The next call
Take a look at a live example from the page with examples.
We have set picks for three properties. The first is a percentage property: the value of the property can be from 0 to 100, what goes beyond the boundaries of this range is automatically converted to a valid value (if less than 0, then the value becomes 0, if more than 100, then the value becomes 100). The second value is a string, the property should always be a string. The third should always be an integer (or
There is another kind of mediator: the mediator of an array element. When you install such a mediator, it will transform each added element the way you want. Take a look at the example from the documentation:
This creates a typed array: an array of strings. Yes, of course, such a typed array differs in performance from built-in typed arrays for the worse. But the ability to validate and transform data now knows no bounds.
Do not forget that the mediator of an array element may be the only one in the whole class. And you can remove the mediator by setting it to
By the way, the example above can be fixed for advanced programmers:
Cool?
After the publication of the first series of articles, habrayuzers criticized some features of Matryoshka. Criticism was justified, and it was decided to review the controversial issues and make corrections. Here are some of them:
1. MK.Array # pop and MK.Array # shift return the deleted item, instead of “yourself”. Starfall : Comment on the article , winbackgo : Comment on the article
2. Default binders for
3. Default binders for
In addition, it was decided to remove the hard dependence on
Balalaika inherits
To use Balalaika directly, the global variable $ b is used :
(It is planned to write a separate post about Balalaika)
banzalik : Comment with a wish
jMas : Another comment
Selects the first element that matches the selector inside the bound to
Selects all elements matching the selector inside bound to
Deletes and returns the item with the specified index.
It is syntactic sugar over
Properties that are always
In addition, several bugs were fixed. Here is a list of fixes:
Following the recommendations of semver.org, obsolete methods and properties will not be removed until release 1.0, but warnings and requests to use new methods will be displayed in the console.
The
Take a look at the example from the Matryoshka website . A more detailed description of the smart array is planned a little later.
In version 1.0 (which is planned about a year later), it is planned, firstly, to remove obsolete methods, and secondly, to remove support for the eighth Donkey. All Internet kittens will be happy when no one else supports IE8.
Despite the apparent silence around the project, Matryoshka is developing. All features are not only thoroughly tested, but also work in live applications.
Another goal of Matryoshka is to make a developer using the framework a “data god”, who fully, 100% controls what is happening in the model, of course, without worrying about the interface. For example, it is planned to implement a popup event of a data change event on a tree of objects and arrays, and this will be very cool. More - more ...
The space that the Matryoshka kernel provides, based on accessors (getters and setters), provides a wide field for programmer's creativity. Agree, the idea of intermediaries and dependencies lay on the surface. Say, at an input, a property is
Thank you for reading (or scrolling) the post to the end. All the rays of good.
(All previous articles have been updated to the current state)
Repository
Site (there is also documentation)
Hello everyone. 5 months have passed since the last publication of a series of articles about Matryoshka. Since then, a small number of errors have been fixed, several convenient features have appeared, including under the influence of your comments, the project has found a sponsor in the person of Shooju , received a logo and a normal, non-bootstrap website.
Let me remind you that Matryoshka is a general-purpose framework in which the importance of data dominates the appearance, and the interface is automatically updated when the data is updated.
Matryoshka makes it quite easy to relate data and presentation elements (for example, the property of an object and the value of an input field) without worrying about further synchronization of data and presentation. For example, the simplest binding looks like this:
Create an instance:
Bind property x to the element
Change data
After we assign property x a different value, the state of the element changes accordingly.
Take a look at a living example.
Another important feature of a nested doll is events (including custom ones). For example, Matryoshka can catch a change in the value of a property:
The code will output
For more information about these and other features, see the links above.
Create an instance:
var mk = new Matreshka();
Bind property x to the element
.my-select
:mk.bindElement( 'x', '.my-select' );
Change data
mk.x = 2;
After we assign property x a different value, the state of the element changes accordingly.
Take a look at a living example.
Another important feature of a nested doll is events (including custom ones). For example, Matryoshka can catch a change in the value of a property:
mk.on( 'change:x', function( evt ) {
alert( 'x изменен на ' + evt.value );
});
The code will output
"x изменен на Привет"
:mk.x = 'Привет';
For more information about these and other features, see the links above.
A bit about article design
I will use jsdoc syntax to denote methods and properties, in particular - a lattice (#) for example,
MK#addDependence
means that I'm talking about a method addDependence
, an instance of a class MK
.Most delicious
Dependencies ( MK # addDependence method )
This coolest method allows you to establish the dependence of some data on others. The first argument is the key of the dependent property, the second is an array of keys on which the property depends (or a string with keys enumerated by a space), the third is a handler function that should return a new value for the property. This is a kind of replacement for getter, with the difference that the getter is called every time you get a property, and
addDependence
calculates the value of the property in advance, when changing the data on which the property depends. You need to work with getters very carefully, since relatively heavy calculations can greatly affect the performance of your code. "Dependencies", in turn, in terms of resource consumption, are no different from the usual processing of data change events and are, in fact, syntactic sugar over them. In addition, the method is another step towards self-documenting code. Say we need a property to
f
always be the sum of the properties a, b, c, d, e
. This is what pure event code looks like:
this.on( 'change:a change:b change:c change:d change:e', function() {
this.f = this.a + this.b + this.c + this.d + this.e;
});
Now compare it with this:
this.addDependence( 'f', 'a b c d e', function() {
return this.a + this.b + this.c + this.d + this.e;
});
Or even with this:
this.addDependence( 'f', 'a b c d e', function( a, b, c, d, e ) {
return a + b + c + d + e;
});
Firstly , we have to do less body movements (no heap needed
'change:'
) Secondly , by the name of the method and arguments, we clearly understand why the corresponding lines of code are created. Translating into human language, the first method can be voiced as follows: "when changing properties,
a, b, c, d, e
do something", and the second way: "add the dependence of the property f
on the properties a, b, c, d, e
." Feel the difference? Thirdly , if one of the properties on which the other property depends is changed with a flag
silent
, the first option will not work. For example, there is the task of calculating the perimeter.
Option 1, on events:
this.on( 'change:a change:b', function() {
this.p = ( this.a + this.b ) * 2;
});
Option 2 using dependencies:
// Вариант 2
this.addDependence( 'p', 'a b', function() {
return ( this.a + this.b ) * 2;
});
Now, if we call:
this.set({
a: 2,
b: 3
}, {
silent: true
});
... then in the first version p
it will not change, in the second - it will change. Please note that if you hung an event handler on a change
p
, and one of the properties on which it depends p
changed with a flag silent
, then, as expected, the change handler p
will not be called.this.on( 'change:p', function() { /* ... */ } );
this.set( 'a', 12, { silent: true }); // для войства "p" изменение тоже будет "тихим"
In the next version, it is planned to add the dependence of the property on data located in other classes (a common task in applications where data dominates the appearance). This is already implemented, but not documented due to language syntax limitations. It is assumed that the dependence on other classes will look like this:
this.addDependence( 'a', [
instance1, 'b c d',
instance2, 'e f g',
this, 'h i j'
], function() { /* ... */ });
Where the odd array element from the second argument is an instance, the even one is a list of keys. It looks specific, I will be glad for other options.
On the page with examples, you can see the method live .
Regarding Rendol 's comment : mapping can be implemented using dependencies.
Mediators (intermediaries)
MK Method # setMediator
Quite often, the task of validating and converting data is involved. Let's say your class has a property
a
that should always be a string and nothing else. Let's try to solve this problem using standard tools:// обработчик-конвертер
this.on( 'change:a', function() {
if( typeof this.a !== 'string' ) {
this.a = String( this.a );
}
});
// какоий-нибудь обработчик1
this.on( 'change:a', function() {
if( typeof this.a === 'string' ) {
/* ... */
}
});
// какоий-нибудь обработчик2
this.on( 'change:a change:b', function() {
if( typeof this.a === 'string' ) {
/* ... */
}
});
// присваиваем число
this.a = 123;
Do you understand what is going on here? The first handler converts
a
to a string, and the last two handlers are forced to check whether it is a a
string, since the converter handler starts all the handlers (including itself) again. Wandering around in search of a solution, such as an event beforechange:%ключ%
, it was decided to introduce a new concept into the framework - the “intermediary”. The mediator (or mediator) changes the value of the property before any event associated with the change of this property is triggered.
Method Syntax
MK#setMediator
it is simple: the first argument is the key for which you want to set the mediator, the second argument is the function that should return the new value of the property. Alternative syntax: a mediator key object is passed to the method for the case if you want to attach several mediators to the class at once. For example, a property
a
should always be a string, and a property b
should always be an integer (or NaN
)this.setMediator( 'a', function( value ) {
return String( value );
});
this.setMediator( 'b', function( value ) {
return parseInt( value );
});
And for those who know Javascript well:
this.setMediator( 'a', String );
this.setMediator( 'b', parseInt );
Mediators are not limited to such simple possibilities. Nothing prohibits making any calculations, but only carefully so as not to harm the performance of the application.
The method is mega-convenient and cool, including when the server accepts a certain type of value. There can be only one mediator. The next call
MK#setMediator
with the same property will block the old pick. In order to remove the "intermediary", you can pass instead of a function null
. Take a look at a live example from the page with examples.
mk.setMediator({
percentageValue: function( v ) {
return v > 100 ? 100 : v < 0 ? 0 : v;
},
stringValue: String,
integerValue: parseInt
});
We have set picks for three properties. The first is a percentage property: the value of the property can be from 0 to 100, what goes beyond the boundaries of this range is automatically converted to a valid value (if less than 0, then the value becomes 0, if more than 100, then the value becomes 100). The second value is a string, the property should always be a string. The third should always be an integer (or
NaN
). Developing the idea, you can create a property that is always true or false, you can create a property that will always be an instance of some class ...MK.Array Method # setItemMediator
There is another kind of mediator: the mediator of an array element. When you install such a mediator, it will transform each added element the way you want. Take a look at the example from the documentation:
var mkArray = new MK.Array( 1, 2, 3, 4, 5 );
mkArray.setItemMediator( function( value ) {
return String( value );
});
mkArray.push( 6, 7 );
mkArray.unshift( true, {} );
console.log( mkArray.toJSON() ); // [ "true", "[object Object]", "1", "2", "3", "4", "5", "6", "7" ]
This creates a typed array: an array of strings. Yes, of course, such a typed array differs in performance from built-in typed arrays for the worse. But the ability to validate and transform data now knows no bounds.
Do not forget that the mediator of an array element may be the only one in the whole class. And you can remove the mediator by setting it to
null
.mkArray.setItemMediator( null );
By the way, the example above can be fixed for advanced programmers:
mkArray.setItemMediator( String );
Cool?
"According to numerous applications"
After the publication of the first series of articles, habrayuzers criticized some features of Matryoshka. Criticism was justified, and it was decided to review the controversial issues and make corrections. Here are some of them:
1. MK.Array # pop and MK.Array # shift return the deleted item, instead of “yourself”. Starfall : Comment on the article , winbackgo : Comment on the article
2. Default binders for
input[type="text"]
and textarea
now listen to the event 'paste'
, and not just 'keyup'
. safron : Comment on article3. Default binders for
input[type="checkbox"]
and input[type="radio"]
now listen to the event'keyup'
. This means that you can work with these elements from the keyboard when binding data to them (same comment).Balalaika
In addition, it was decided to remove the hard dependence on
jQuery
. In my opinion, it jQuery
’s a wonderful library, but losing relevance in new browsers. Now, if it’s not on the page jQuery
, it is replaced by a mini library, which I called “Balalaika” (note: only if not; if jQuery
connected, it is still used jQuery
). Balalaika inherits
Array.prototype
, so developers have access to all methods kotorue have the array, plus jQuery
compatible methods for working with classes ( addClass
, removeClass
, hasClass
), events ( on
, off
), parsing the HTML ( parseHTML
), and others. To use Balalaika directly, the global variable $ b is used :
$b( 'div' ).forEach( function(){ /* ... */ } );
$b( '.blah-blah', context ).is( 'div' );
$b( 'input[type="text"]' ).on( 'keydown', handler );
(It is planned to write a separate post about Balalaika)
banzalik : Comment with a wish
jMas : Another comment
Other innovations
MK # select method
Selects the first element that matches the selector inside the bound to
this
(key "__this__"
, see previous articles). The method was created for simplified work with individual elements, and not with collections of elements.this.select( '.blah-blah' );
Method MK # selectAll
Selects all elements matching the selector inside bound to
this
. Does the same as the method $
(dollar sign). MK#selectAll
created to complete the set of methods: if there is a “select” ( MK#select
) method, then there must be a “select all” method.this.selectAll( '.blah-blah' );
// то же самое, что и
this.$( '.blah-blah' );
MK.Array # pull method
Deletes and returns the item with the specified index.
var x = this.pull( 3 );
It is syntactic sugar over
splice
.var x = this.splice( 3, 1 )[ 0 ];
Properties isMK , isMKArray and isMKObject
Properties that are always
true
in instances of the corresponding classesvar mkObject = new MK.Object();
alert( mkObject.isMK && mkObject.isMKObject ); // true
Fixes
In addition, several bugs were fixed. Here is a list of fixes:
- Do nothing if, as an argument, the MK.Object # addJSONKeys and MK.Object # removeJSONKeys methods are passed
undefined
(or nothing is passed). - You can use numbers in MK.Object # addJSONKeys , MK.Object # removeJSONKeys , MK # remove methods
- Fixed MK # once method
Renamed Methods and Properties
Following the recommendations of semver.org, obsolete methods and properties will not be removed until release 1.0, but warnings and requests to use new methods will be displayed in the console.
- MK.elementProcessors -> MK. defaultBinders
- MK # el -> MK # bound
- MK # $ el -> MK # boundAll
- MK.htmlp -> MK. binders.innerHTML ()
- MK.classp () -> MK. binders.className ()
Smart Array
The
MK.Array
plugin MK.DOMArray
was mentioned, which was mentioned in the article about MK.Array
. That is, the functionality that the "to attract attention" GIF reflected was working out of the box. Let me remind you that the plugin MK.DOMArray
changes the DOM automatically when the array changes (add, delete, sort ...). Take a look at the example from the Matryoshka website . A more detailed description of the smart array is planned a little later.
"Road map"
- Implement a replaceable property
Model
(which will be similar tomodel
fromBackbone
). This feature will be syntactic sugar over the mediator of the array element. - Lazy initialization. Now, when inheriting, you must always call the method
initMK
. Not kosher. - Rewrite the event engine. Perhaps, the DOM interface will be taken as the basis
EventTarget
. - Update the method
MK#addDependence
for dependencies on other class instances (as described above). - Optimize the code for the minifier.
- Correct texts on the site. The site, as you can see, is in English, and there are errors in the text. You can help correct errors by using the combination Ctrl + Enter after selecting the text in which there is an error (so as not to make the request pool). I'll be very grateful.
In version 1.0 (which is planned about a year later), it is planned, firstly, to remove obsolete methods, and secondly, to remove support for the eighth Donkey. All Internet kittens will be happy when no one else supports IE8.
In conclusion
Despite the apparent silence around the project, Matryoshka is developing. All features are not only thoroughly tested, but also work in live applications.
Another goal of Matryoshka is to make a developer using the framework a “data god”, who fully, 100% controls what is happening in the model, of course, without worrying about the interface. For example, it is planned to implement a popup event of a data change event on a tree of objects and arrays, and this will be very cool. More - more ...
The space that the Matryoshka kernel provides, based on accessors (getters and setters), provides a wide field for programmer's creativity. Agree, the idea of intermediaries and dependencies lay on the surface. Say, at an input, a property is
value
always a string, so that we do not put it there, the propertyvalueAsNumber
always a number that depends on the string value ... Thank you for reading (or scrolling) the post to the end. All the rays of good.
Only registered users can participate in the survey. Please come in.
Do you use Matryoshka?
- 3.2% Yes, I use (I will certainly use) 8
- 41.8% Ideas are interesting, but try 102
- 32.3% Interesting, but dumb. I will follow the further development of the project 79
- 22.5% I won’t even try. The framework has no future 55