📜 ⬆️ ⬇️

A practical example of using Backbone

In this article we will discuss the use of Backbone, and in particular, code examples working with the server. This should be a certain intermediate point in the wanderings of the seeker, because otherwise it is very difficult to start using it, and the probability of abandoning the idea of ​​transition tends to unity.

Why do we need this publication? There have already been articles on the topic, but they affect only very superficially what is written in the documentation, although it would be necessary to show undocumented paths. That's right: the backbone is not a comprehensive standalone library like Jquery, which you can’t touch or break. This library is intended only to build an approximate structure; we can sculpt from this material what we need. Once again: there is no point in looking for ready-made patterns, the letter in the letter does not need to be reprinted; it will not help anyway. You need to learn how to use the tool, and then rush into battle.

So, you crossed the line habrakata. My goal is not to explain the basic principles of the library, there were already plenty of articles:
habrahabr.ru/blogs/javascript/129928
habrahabr.ru/blogs/javascript/118782
habrahabr.ru/blogs/webdev/123130

I note that all three describe the standard use of Backbone, but very rarely do you really need, for example, to use a router. Or you need to trite to contact the server - and how to do it? Everyone refers to Backbone.sync, and for some reason nobody provides examples. Consider the previous sentence one of the main reasons for writing this note. If you do not agree with him - then you can not read.
')
Let's start. We will write frontend editing notes. Focus on the scripts, blatantly ignoring both the aesthetic wishes of users and the right of choice: I will test only in chrome. Links to the example and the code in the archive will be given at the end.

What do we need to get started? Create an empty xhtml page with a standard structure, connect jquery, underscore, backbone (in that order). At the end add a link to our script. On the server side, we create a php file that will be responsible for reading / writing data (lies in the archive, app.php, I will not give the code, the script simply processes requests like? Method =).

When the preparations are finished, let's start writing a script in js. Create a container for storing models and log:
app = { debug: true, log: function(obj) { if(this.debug) { console.log(obj); } }, models: {} } 

The function Backbone.sync is designed so that it is very easy to re-declare, without spoiling anything. In addition, each model can have its own synchronization method (guess what it should be called?). We will write a global function for our entire script. Goals pursued by us:

What happened with me (your implementation may differ):
 Backbone.sync = function(method, model, options) { //     var method = (method=='update'||method=='create')?'save':method; //    if(model.loading && model.loading.method == method) { model.loading.xhr.abort(); } app.log('  "'+model.url(method)+'"'); var xhr = $.ajax({ type: 'POST', url: model.url(method), data: (model instanceof Backbone.Model)?model.toJSON():{}, success: function(ret) { //    if(ret.is_error) { app.log(' '); } else { app.log(' '); (function(data){ app.log('Backbone.sync  :', data); if(data.res) { //  - ,   model.trigger('load:res', data.res); } else { //  - ,   options.success(data.rows?data.rows:data); } model.trigger((method=='save')?'save':'load', data); })(ret.data); } }, error: function (req_obj, msg, error) { app.log(' '); }, dataType: 'json' }); //       model.loading = { method: method, xhr: xhr } }; 

I'm a little deceitful. If you call methods in the model like this: read list read, then the last read will not break the first one, but the article is not about that, so we put a huge bolt.

Record Model Code:
 app.models.note = (Backbone.Model.extend({ defaults: { id: 0, text: '' }, url: function(method){ return './app.php?method='+method; } })); app.models.Note = (Backbone.View.extend({ tagName: 'li', className: 'entity', render: function(){ var data = this.model.toJSON(); var that = this; $(this.el).html('').data('rowId', data.id); $(this.el).append($('<input type="text" />').val(data.text)); $(this.el).append($('<button></button>').click(function(){ app.models.page.trigger('post:save', { 'id': $(this).closest('li').data('rowId'), 'text': $(this).closest('li').find('input').val() }); })); $(this.el).append($('<button></button>').click(function(){ if(!confirm(' ,     ?')) return; app.models.notes.get($(this).closest('li').data('rowId')).destroy(); })); return this; } })); 

List of entries:
 app.models.notes = new (Backbone.Collection.extend({ model: app.models.note, initialize: function(){ this.bind('destroy', function(){ this.reload(); }, this); }, reload: function(){ var that = this; var options = ({ error:function(){ app.log('  !'); that.trigger('change'); }, success: function(){ app.log(' '); that.trigger('change'); } }); app.log(' ...'); this.fetch(options); }, url: function(method){ return './app.php?method=list'; } })); 

And last, the page model:
 app.models.page = new (Backbone.View.extend({ el: null, el_list: null, notes: null, initialize: function(){ this.bind('page:load', this.pageLoad, this); this.bind('list:reload', this.listReload, this); this.bind('post:save', this.postSave, this); this.notes = app.models.notes; this.notes.bind('change', this.onListChange, this); this.notes.bind('load:res', this.onListChange, this); return this; }, pageLoad: function(data) { var that = this; this.el = $('.layout'); this.el_list = this.el.find('.items-list'); //   this.el.find('.title .refresh').bind('click', function(){ that.trigger('list:reload') }); //   this.el.find('.items-add-submit').bind('click', function(){ that.trigger('post:save', { id: false, text: $('.items-add-text').val() }); }); this.trigger('list:reload'); }, render: function(ret){ $(this.el_list).html(''); if(!ret) { app.log(' . : '+this.notes.length); _(this.notes.models).each(function(item){ this.appendItem(item); }, this); } else { app.log(' . : "'+ret+'"'); $(this.el_list).html('').append($('<li class="res"></li>').text(ret)); } return this; }, appendItem: function(item) { var view = new app.models.Note({ model: item }); $(this.el_list).append(view.render().el); }, onListChange: function(ret){ this.render(ret); }, postSave: function(obj){ var model = new app.models.note(); if(obj.id) { model.set({ id:obj.id }); } model.set({ text:obj.text }); model.save(); this.trigger('list:reload'); }, listReload: function(){ this.notes.reload(); } })); 

Forgot something ... Oh yeah, we start rendering:
 $(document).ready(function(){ app.models.page.trigger('page:load'); }); 


As you can see, everything is simple. I intentionally gave the code in pieces, instead of chewing each function, since The article is focused on a person at least a little familiar with js / backbone. If this is not about you - I gave the links above, everything is described there in detail. If there are difficulties in understanding or need additional explanations to the code - write.
Code in action: yurov.me/art
All code in the archive: yurov.me/art/art.tar.gz

Ps server code is oak, glitches are possible. It is important to show the frontend. If it does not work, you can try to run it locally or just browse the archive.

PPS Comrade oWeRQ put the code in order, I will update the article later (its code is much cleaner):
owerq.dyndns.org/test/art

Source: https://habr.com/ru/post/132728/


All Articles