Backbone - небольшая библиотека на javascript, которая структурирует клиентский код. Чаще всего, Backbone используется для создания одностраничных приложений.
Продолжаем наше ускоренное изучение библиотеки Backbone. Мы хотели узнать, как реализовать создание, чтение, обновление и удаление для моделей!
Создание моделей
Мы уже умеем создавать список элементов из консоли, а также из пользовательского интерфейса (2.4.3), так что будем считать, что этому мы уже научились.
Обновление моделей
Что делать, если вы сделали ошибку в слове и хотите изменить текст из списка ваших дел? Кроме того, вы можете заметить, что чекбоксы не сохраняют своего состояния при перезагрузке страницы. Давайте исправим обе эти проблемы.
Вы хотите ответить на событие, появляющееся в окне с текстом, который может быть исправлен пользователем по двойному клику. Для этого, во-первых, давайте добавим следующий HTML-код в шаблон item-template под тегом label.
<input class="edit" value="<%- title %>">
Если вы обновите страницу, вы заметите, что оба они отображаются одновременно. Таким образом, вы можете скрывать их с помощью следующего CSS:
#todo-list input.edit {
display: none; /* Скрываем строку ввода */
}
#todo-list .editing label {
display: none; /* Скрывает текст метки при .editing */
}
#todo-list .editing input.edit {
display: inline; /* Показывает текст в строке ввода при .editing */
}
Далее нам нужно добавить события к классу TodoView, чтобы реагировать на изменения.
// // рендерит список отдельных задач (li)
app.TodoView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#item-template').html()),
render: function(){
this.$el.html(this.template(this.model.toJSON()));
this.input = this.$('.edit');
return this; // Включить в цепочку вызовов
},
initialize: function(){
this.model.on('change', this.render, this);
},
events: {
'dblclick label' : 'edit',
'keypress .edit' : 'updateOnEnter',
'blur .edit' : 'close'
},
edit: function(){
this.$el.addClass('editing');
this.input.focus();
},
close: function(){
var value = this.input.val().trim();
if(value) {
this.model.save({title: value});
}
this.$el.removeClass('editing');
},
updateOnEnter: function(e){
if(e.which == 13){
this.close();
}
}
});
Удаление моделей
Чтобы иметь возможность удалять элементы списка, мы должны добавить кнопку удаления в каждый элемент и слушать событие щелчка на нем, который вызовет функцию destroy() (уничтожить) в выбранном объекте Todo.
Вставьте HTML-разметку для кнопки Удалить.
<script type="text/template" id="item-template">
<div class="view">
<input class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>>
<label><%- title %></label>
<input class="edit" value="<%- title %>">
<button class="destroy">Удалить</button>
</div>
</script>
Добавьте прослушивайте событие щелчка по кнопке, которую только что создали.
},
initialize: function(){
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this); // удаление
},
events: {
'dblclick label' : 'edit',
'keypress .edit' : 'updateOnEnter',
'blur .edit' : 'close',
- 'click .toggle': 'toggleCompleted'
+ 'click .toggle': 'toggleCompleted',
+ 'click .destroy': 'destroy'
},
edit: function(){
this.$el.addClass('editing');
Добавьте метод destroy
в TodoView для удаления модели.
},
toggleCompleted: function(){
this.model.toggle();
- }
+ },
+ destroy: function(){
+ this.model.destroy();
+ }
});
Вы можете увидеть результат нашей работы здесь. Введите текст в поле ввода и нажмите на клавишу ENTER. О боже, мы ввели нечто нечиталельное. Надо срочно исправлять. Щелкните быстро два раза по введенному слову и исправьте его на что-то осмысленное.
Маршрутизация с помощью Backbone.Router
Вы могли бы построить веб-приложение без использования маршрутизаторов. Однако, если вы хотите сделать ссылку на «определенное состояние» или адрес Web-приложения, на которое нужно сделать ссылку. Это тот самый случай, когда маршрутизаторы приходят на помощь.
Маршрутизация в большинстве применения JS достигается с помощью Хештегов. Например, если вы взгляните на URL Gmail вы увидите что-то вроде:
https://mail.google.com/mail/u/0/#inbox/139c0d48e11d986b
Здесь #inbox/139c0d48e11d986b
это хештег, который ссылается некоторой электронное местоположение.
В Backbone маршруты – это хэш-карты, которые сопоставляют ссылки с функциями. Вы можете использовать части параметров, таких как todos/:id
, или с помощью знака *
(файл/*путь) вы сопоставите все параметры знаков. Для этого параметры знаков должны всегда сопоставляться в конце.
В нашем приложении мы будем использовать маршруты для фильтрации заданий, которые уже сделаны и которые выполнить еще только предстоит. Итак, давайте инициализируем наши маршруты:
app.Router = Backbone.Router.extend({
routes: {
'*filter' : 'setFilter'
},
setFilter: function(params) {
console.log('app.router.params = ' + params); // только в учебных целях
window.filter = params.trim() || '';
app.todoList.trigger('reset');
}
});
Теперь необходимо инициализировать его, добавив эти строки:
//--------------
// Инициализаторы
//--------------
+ app.router = new app.Router();
+ Backbone.history.start();
app.appView = new app.AppView();
Вы можете убедиться, что ваш маршрутизатор работает просто набрав #anything/that/you/want
и увидев параметр в консоли браузера. Поговорим теперь об обработке маршрутов.
Перед рендерингом списка объектов нужно проверить параметры, чтобы показывать только невыполненные, выполненные или все задания. Это показано на фрагменте кода ниже:
},
addAll: function(){
this.$('#todo-list').html(''); // очистить список задач
- app.todoList.each(this.addOne, this);
+ // отфильтровать список задач
+ switch(window.filter){
+ case 'pending':
+ _.each(app.todoList.remaining(), this.addOne);
+ break;
+ case 'completed':
+ _.each(app.todoList.completed(), this.addOne);
+ break;
+ default:
+ app.todoList.each(this.addOne, this);
+ break;
+ }
},
newAttributes: function(){
return {
При попытке добавить #/pending
или #/completed
в конце URL вы получите сообщение об ошибке! Это хороший знак, который говорит нам о том, что маршруты работают, но мы еще не выполнили app.todoList.remaining()
и app.todoList.completed()
. Проделайте следующее:
//--------------
app.TodoList = Backbone.Collection.extend({
model: app.Todo,
- localStorage: new Store("backbone-todo")
+ localStorage: new Store("backbone-todo"),
+ completed: function() {
+ return this.filter(function( todo ) {
+ return todo.get('completed');
+ });
+ },
+ remaining: function() {
+ return this.without.apply( this, this.completed() );
+ }
});
Теперь, если вы снова попытаетесь добавить хеш-теги, то все будет работать! Но, будет лучше, если пользователь сможет переходить по ссылкам, вместо того, чтобы вводить URL. Так, давайте же добавим их.
<header id="header">
<h1>Todos</h1>
<input id="new-todo" placeholder="Что нужно сделать?" autofocus>
+ <div>
+ <a href="#/">Показать все</a> |
+ <a href="#/pending">Показать невыполненные</a> |
+ <a href="#/completed">Показать сделанное</a>
+ </div>
</header>
<section id="main">
<ul id="todo-list"></ul>
Ну, вот и все! Если вы внимательно читали наше руководство по Backbone, то уже можете работать с основными модуями Backbone (Модели, Коллекции, Представления, События и Маршруты) и создать свое собственное одностраничное приложение. Если же вы все еще испытываете затруднение, то рекомендуем вам изучить Одностраничное приложение на Backbone.