Working with data models in javascript
- From the sandbox
- Tutorial
Hello, Habralyudi.
Small by little, from my experience and our projects, a small library was born for working with models in javascript. It is called Model.js .
I will tell you briefly about this library and in this post I request feedback from those who, by creating complex javascript applications, already solve this problem in a certain way without frameworks. The opinion of those who are just looking for the right tool for their needs is also interesting: what tool do you need and how much does Model.js suit you ?
To simplify working with the data layer, without using frameworks. The current first version of the library - v0.1 weighing about 12K - is designed to help primarily with data validation and event management, in particular with events when data changes.
Sugar. An ordinary pleasing to the eye syntactic sugar.
The model described is nowhere simpler.
Then we create entities, as usual objects.
Getters of attribute values. In our example, this is:
Setters In addition to changing values, the change event is also fired .
The getter will
Setters
It's all.
You may ask, where are the conservation methods and so on? - I will answer: the use of the library implies that the developer must implement these methods independently as required by the logic of his application.
It should be noted that with saving there is one nuance: if the data was saved successfully, you need to inform the entity about it using a private method
An example explanation is good. Let's say our application runs in a browser environment and the method
When creating a model, each of its attributes is necessarily described.
In general, validators are ordinary functions that take values and return errors when these values are invalid.
If you need to use the validator several times, it is reasonable to register it in order to connect by name.
Model.js has multiple base (already recorded) validators:
To pass the parameter to the validator when describing the attribute, you need to write it, as in the example below, in the form of an array:
Validators can be connected with the usual grandfather method, without registering them.
All this is necessary so that he
There are four events:
Now Model.js is a pure state of the art , it is an intermediate, but confidently working result. If you are interested in the library, if you have a desire to try to use it, I will be happy to answer your questions. More information on what works can be found in the documentation on the github and in the tests.
In the meantime, wish the baby a good journey, because in order to become an “adult” library, she still needs to do a lot of work.
Small by little, from my experience and our projects, a small library was born for working with models in javascript. It is called Model.js .
I will tell you briefly about this library and in this post I request feedback from those who, by creating complex javascript applications, already solve this problem in a certain way without frameworks. The opinion of those who are just looking for the right tool for their needs is also interesting: what tool do you need and how much does Model.js suit you ?
What for?
To simplify working with the data layer, without using frameworks. The current first version of the library - v0.1 weighing about 12K - is designed to help primarily with data validation and event management, in particular with events when data changes.
What is so special?
Sugar. An ordinary pleasing to the eye syntactic sugar.
The model described is nowhere simpler.
var Note = new Model('Note', function () {
this.attr('id!', 'number');
this.attr('title', 'string', 'nonempty');
this.attr('text', 'string');
});
Then we create entities, as usual objects.
var note = new Note({ id: 123, title: "Hello World" });
Entity Public Properties
Getters of attribute values. In our example, this is:
note.data.id
note.data.title
note.data.text
Setters In addition to changing values, the change event is also fired .
note.data.id =
note.data.title =
note.data.text =
note.data = {…}
The getter will
note.get(attrName[, attrName, …])
return an object with the values of the requested attributes. note.get()
will return a copy of all data. note.data()
- the same as note.get()
. Setters
note.set(attrName, value)
and note.set({…})
not "shoot" change event. note.hasChanged
says whether the entity data has changed since it was last saved. note.isNew
says whether the entity data is saved at least once. note.isPersisted
says whether recent changes are saved. note.bind(eventName, handler)
"Hangs" the handler. By the way, you can hang the handler of any event not only on a separate entity, but on all entities of the class ( Note.bind
). note.isValid
says whether current model data is valid. note.errors
in fact, returns data errors, if any. note.revert()
rolls back unsaved changes and “shoots” the event revert
.It's all.
You may ask, where are the conservation methods and so on? - I will answer: the use of the library implies that the developer must implement these methods independently as required by the logic of his application.
It should be noted that with saving there is one nuance: if the data was saved successfully, you need to inform the entity about it using a private method
note._persist()
, which also “shoots” the event persist
. An example explanation is good. Let's say our application runs in a browser environment and the method
note.save()
should save data using ajax.Note.prototype.save = function () {
var note = this;
return $.ajax({
type: 'PUT',
url: '/notes/'+note.data.id,
data: note.data(),
dataType: 'json'
}).done(function (json) {
note._persist();
});
}
note.bind('persist', function () {
$('h1', 'div#note'+this.data.id).html(this.data.title);
});
note.data = { id: 123, title: "abc", text: "" }
if (note.hasChanged && note.isValid) { // оппа Django-style
note.save();
}
Data checking
When creating a model, each of its attributes is necessarily described.
this.attr('title', 'string', 'nonempty')
First, indicate the attribute name, then its validators. Validators, when the time comes, will check the value of the attribute in the declared order. In general, validators are ordinary functions that take values and return errors when these values are invalid.
function validateMinLength(value, minLength) {
if (value.length < minLength) return 'tooshort';
}
If you need to use the validator several times, it is reasonable to register it in order to connect by name.
Model.registerValidator('array', function (value) {
if (Object.prototype.toString.call(v) === '[object Array]') return 'wrongtype';
});
Model.registerValidator('minLength', validateMinLength);
Model.js has multiple base (already recorded) validators:
number
, string
, boolean
, nonnull
, nonempty
and in
. They, just like in our example, can be connected to attributes by name. To pass the parameter to the validator when describing the attribute, you need to write it, as in the example below, in the form of an array:
this.attr('title', 'string', 'nonempty', [ 'minLength', 6 ]);
Validators can be connected with the usual grandfather method, without registering them.
this.attr('title', 'string', 'nonempty', [ 'minLength', 6 ], function (title) {
if (title[0] !== title[0].toUpperCase()) return 'downcase';
});
All this is necessary so that he
note.isValid
could say true
or false
, and he note.errors
could return the object with errors, if any.note.data = { id: 'abc', title: '', text: 3 }; // полностью неверные данные
note.isValid // false
note.errors // { id: 'wrongtype', title: 'empty', text: 'wrongtype' }
Events
There are four events:
initialize
, change
, persist
and revert
. As mentioned above, you can hang the handler on a specific entity ( note.bind
), or you can also hang it on a class ( Note.bind
), so that the handler will become common to all entities. initialize
"Fired" once when creating the entity: var note = new Note({…})
. So it initialize
only makes sense to hang up a handler on a class. change
triggered every time an attribute value changes. There are, however, setters who do not pull change (this was described above). perist
- when the entity receives a signal that the changes have been successfully saved. revert
- when the application logic ordered to roll back yet unsaved changes (using the method note.revert()
).var ALLOWED_LANGUAGES = ['en', 'ua', 'ru'];
var Note = new Model('Note', function () {
this.attr('id!', 'number');
this.attr('title', 'string', 'nonempty');
this.attr('lang', 'string', 'nonempty', [ 'in', ALLOWED_LANGUAGES]);
this.attr('text', 'string');
});
Note.bind('initialize', function () {
if (!this.data.lang) {
this.set('lang', 'en'); // change не выстрелит — специальный такой сеттер!
}
});
note.bind('change', function (changes) {
if (changes.title) $('h1', 'div#note'+this.data.id).html(changes.title);
});
In conclusion
Now Model.js is a pure state of the art , it is an intermediate, but confidently working result. If you are interested in the library, if you have a desire to try to use it, I will be happy to answer your questions. More information on what works can be found in the documentation on the github and in the tests.
In the meantime, wish the baby a good journey, because in order to become an “adult” library, she still needs to do a lot of work.