пятница, 19 сентября 2014 г.

Backbone - общая структура

Главная концепция - держать данные отдельно от ДОМа страницы, так креши во вью не приводят к потерям данных на странице.

Создание модели

var MyModel = Backbone.Model.extend({});

var myModel = new MyModel({myField: "..."});
myModel.set('myField', 'some value');

Создание вьюхи:

var MyView = Backbone.View.extend({
  render: function(){
   $(this.el).html('<li>' + this.model.get('myField')  + '</li>
');
  }
});

var myView = new MyView({model: myModel});
myView.render();
$('#app').html(myView);



Модель

Получение данных с сервера в модель и обратно

Хард вей:)

myModel.url = '/someurl';
myModel.fetch();
alert(myModel.get('field1'));

RESTful way(CRUD):

var TodoItem = Backbone.Model.extend({urlRoot: '/todos'});
var todoItem = new TodoItem({id: 1});
todoItem.fetch();//GET /todos/1
//--> { id: 1, description: 'Pick up milk', status: 'incomplete' }

todoItem.set({description: 'Pick up cookies.'});
todoItem.save();//PUT /todos/1 with JSON params
var todoItem2 = new TodoItem();
todoItem2.set({description: 'Fill prescription.'});
todoItem2.save();//POST /todos with JSON params
todoItem2.get('id');//-->2
todoItem2.destroy();//DELETE /todos/2

Получить JSON из модели:
todoItem.toJSON();
//--> { "id": "1", "description": "Pick up milk", "status": "incomplete" }

Значения по-умолчанию:

var TodoItem = Backbone.Model.extend({
  defaults: {
    description: 'Empty todo...',
    status: 'incomplete',
    date: new Date()//each item gets one time
  }
});
var TodoItem = Backbone.Model.extend({
  defaults: function(){
    return {
      description: 'Empty todo...',
      status: 'incomplete',
      date: new Date()//each item gets time of its creation
    };
  }
});

Ивенты:

Build-in:

var doThing = function() {
  ...
};
todoItem.on('change', doThing);
todoItem.set({description: 'Fill prescription.'});//Event triggered on change
todoItem.set({description: 'Fill prescription.'}, {silent: true});//Set without triggering event

todoItem.off('change', doThing);
change When an attribute is modified
change:<attr> When <attr> is modified
destroy When a model is destroyed
sync Whenever successfully synced
error When model save or validation fails
all Any triggered event

Кастомные

todoItem.on('event-name', function(){
  alert('event-name happened!');
});

todoItem.trigger('event-name');

View

Мо умолчанию обвертка div, но мы можем поменять:
var SimpleView = Backbone.View.extend({tagName: 'li'});
var simpleView = new SimpleView();
console.log(simpleView.el);//--> <li></li>
И с детальками:
var TodoView = Backbone.View.extend({
  tagName: 'article',
  id: 'todo-view',
  className: 'todo'
});
var todoView = new TodoView();
console.log(todoView.el);
//--> <article id="todo-view" class="todo"></article>
Backbone по-умолчанию испльзует underscore lib для шаблонов:
var TodoView = Backbone.View.extend({
  ...
  template: _.template('<h3'><%= description %><h3>'),
  render: function(){
    var attributes = this.model.toJSON();
    this.$el.html(this.template(attributes));//чтобы пользоваться $el, нужно чтобы был подгружен jQuery
  }
});

События во вью:

var TodoView = Backbone.View.extend({
  events: {
    "click h3": "alertStatus"
  },
  
  alertStatus: function(e){
    alert('Hey you clicked the h3!');
  }
});
// внутри this.$el.delegate('h3', 'click', alertStatus);

var SampleView = Backbone.View.extend({
  events: {
    "<event> <selector>": "<method>"
  },
  ...
});
Когда подключен jQuery View может работать со следующими событиями:
change
focusout
mousedown
mouseover
select
click
hover
mouseenter
mouseup
unload
dblclick
keydown
mouseleave
ready
focus
keypress
mousemove
resize
focusin
load
mouseout
scroll

 Взаимоподвязка модели и вьюхи.

var AppointmentView = Backbone.View.extend({
  template: _.template('<span class="<% if(cancelled) print("cancelled") %>">' +
                        '<%= title %></span>' +
                        '<a href="#">x</a>'),

  events:  { "click a": "cancel" },
  initialize: function(){
    this.model.on('change', this.render, this);
  },
  cancel: function(){
    this.model.cancel();
  },
  render: function(){
    this.$el.html(this.template(this.model.toJSON()));
  }
});

Колекции

var TodoList = Backbone.Collection.extend({
  model: TodoItem
});
Возможные операции:
todoList.length;//-->2
todoList.add(todoItem1);
todoList.at(0);//at index
todoList.get(1);//by id
todoList.remove(todoItem1);
todoList.reset([
  {description: 'Pick up milk', status: 'incomplete'},
  {description: 'Get a car wash', status: 'incomplete'},
  {description: 'Learn Backbone', status: 'incomplete'}
]);//колекция заполняется указанными моделями и стирает все что в ней было
Получать JSON данные из сервера:
var TodoList = Backbone.Collection.extend({
  url: '/todos'
});
todoList.fetch();// GET /todos
/* [
 *   {description: 'Pick up milk', status: 'incomplete', id: 1},
 *   {description: 'Get a car wash', status: 'incomplete', id: 2}
 * ]
*/
todoList.length; //-->2

События:

//listen for reset
todoList.on('reset', doThing);

//Event triggered on reset & fetch
todoList.fetch();
todoList.reset();

//without notification
todoList.fetch({silent: true});
todoList.reset({silent: true});

Встроенные:
add, remove, reset
События запущенные в модели, также будут срабатывать в колекции:
change, change: <attr>, destroy, sync, error, all

Манипуляции с колекцией

Функции из underscorejs для колекции поставлены вместе с бекбоновской колекцией.

Views & Collections

Колекция ничего не отрисовывывает сама, она все делегирует моделям каждого елемента, а они уже каждой своей вьюшке.
var Appointment = Backbone.Model.extend({});

var AppointmentView = Backbone.View.extend({
  initialize: function(){
    this.model.on('hide', function(){
      this.remove();
    }, this);
  },
  template: _.template('<span class="<%= if(cancelled) print("cancelled") %>">' +
                        '<%= title %></span>' +
                        '<a href="#">x</a>'), 
  render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  },
  remove: function(){
    this.$el.remove();
  }
};
 
var AppointmentList = Backbone.Collection.extend({
  model: Appointment,
  initialize: function(){
    this.on('remove', function(model){
      model.trigger('hide');
    });  
  }
});
var appointments = new AppointmentList();

var AppointmentListView = Backbone.View.extend({
  initialize: function(){
    this.collection.on('add', this.addOne, this);
    this.collection.on('reset', this.render, this);
  },
  render: function(){
    this.collection.forEach(this.addOne, this);
  },
  addOne: function(model){
    var appointmentView = new AppointmentView({model: model});
    this.$el.append(appointmentView.render().el);
  }
});
var appointmentsView = new AppointmentListView({
  collection: appointments
});
$('#app').html(appointmentsView.render().el);

Router & History

Router

var router = new Backbone.Router({
  routes: {
    'todos': 'index',//when the url path is /todos or #todos
    'todos/:id': 'show'
  },
  index: function(){...},
  show: function(id){...}
});

matcherURLparams
search/:query search/ruby query='ruby'
search/:query/p:page search/ruby/p2 query='ruby', page=2
folder/:name-:mode folder/foo-r query='foo', mode='r'
file/*path file/hello/world.txt path='hello/world.txt'

History

Backbone.history.start();
router.navigate('todos/1');//-->#todos/1
Backbone.history.start({pushState: true});//HTML5 Push State
router.navigate('todos/1', {trigger: true});//-->/todos/1

Пример приложения:
var TodoRouter = Backbone.Router.extend({
  routes: { 
    "": "index",
    "todos/:id": "show"
  },
  index: function(){
    this.todoList.fetch();
  },
  show: function(id){
    this.todoList.focusOnTodoItem(id);
  },
  initialize: function(options){
    this.todoList = options.todoList;
  }
});

var todoList = new TodoList();
var TodoApp = new TodoRouter({todoList: todoList});

Или вот так:
var TodoApp = new (Backbone.Router.extend({
  routes: { 
    "": "index",
    "todos/:id": "show"
  },
  initialize: function(options){
    this.todoList = new TodoList();
    this.todosView = new TodoListView({collection: this.todoList});
    $('#app').append(this.todosView.el);
  },
  start: function(){
    Backbone.history.start({pushState: true});
  },
  index: function(){
    this.todoList.fetch();
  },
  show: function(id){
    this.todoList.focusOnTodoItem(id);
  }
}));

...
//and on page
$(function(){ TodoApp.start(); });

https://upcase.com/backbone-js-on-rails
http://recipeswithbackbone.com/
http://ricostacruz.com/backbone-patterns/
https://github.com/codeschool-courses/anatomyofbackbone


Комментариев нет:

Отправить комментарий