Pull to refresh

Comments 37

Самым важным — связкой с сервером. Я ведь с этого начал заметку.
Что то связку с сервером я не увидел толком. Да данные для асинхронных запросов я вижу, но зачем переписывать Backbone.Sync? Чтобы посылать всё через POST? у модели и коллекции есть четыре метода, по одному на каждый из запросов: Get Post и тд. Можно было юзать их и просто передавать функции успеха и эррора. Дальше, что вобще за идея такая появилась отдать success на выполнение и проверить там на error ещё раз? Это ашипко в логике бэкэнда явно...

Было бы лучше более интересно посмотреть на танцы с бубном между бэкбоном и какими то самопальными рест сервисами хотябы, или респонзами из PHP. Лично я в своё время промониторил все статьи по бэкбону, но с вашей ничего полезного и нового не вытянул
>статья ориентированна на человека хоть немного знакомого с js/backbone.
А зачем она ему тогда?
Объясню на своем примере.
Почитал я о backbone. Решил что ООП и mvc на клиенте — это круто. Что дальше? Модели? Коллекции? Я полностью дважды перечитывал (ну не полностью, процентов 60) доки. А толку? Буквально, там так и написано:
documentcloud.github.com/backbone/
«Backbone.sync is the function that Backbone calls every time it attempts to read or save a model to the server… You can override it in order to use a different persistence strategy, such as WebSockets, XML transport, or Local Storage.»:
«Backbone.sync — функция для связи с сервером. Вы можете ее переписать, чтобы хранить данные иначе.». И Че?
После подробного изучения мне понадобилась куча времени, чтобы разобраться с тем, как модели и коллекции взаимосвязаны (именно внутренние связи библиотеки), как backbone парсит данные (что он делает с ответом? Просто перезаписывает данные модели? Обновляет ли он каждую?) и т.д. Из-за этих сложностей сходу его поднять не просто, но как разберешься — сразу все становится простым для понимания. Эта статья для новичков, которые на backbone не писали, но знакомы с основами.
Об этом я, кстати, тоже писал вначале, чтобы не возникало подобных вопросов.
А зачем вы вызов Backbone.[View|Model].extend оборачиваете в ();?
Я сталкивался со случаем, когда без внешних скобок код не работал. Тут есть описание проблемы:
stackoverflow.com/questions/3796308/parenthesis-around-functions-in-javascript

Да и логически это может быть удобнее. Помешать точно не сможет, лучше перестраховаться.
Одно дело — вокруг function (...) {… }, другое дело — вокруг обычного выражения. Зачем???
Я ведь не лабораторную писал. Сработала многолетняя привычка экранировать/закрывать/обрамлять все, что может потенциально что-то нарушить. Здесь действительно скобки лишние.

В любом случае, ссылка выше может быть полезна тем, кто не знал об этом.
Перестраховаться? Карго-культ? Они там не нужны.
А вот ничего подобного. Только что убрал — перестало работать. Копаю.
Я даже fiddle создал. Вы говорили очень умно, так что я запутался. Они там очень критичны. Посмотрите пояснение тут:
jsfiddle.net/nick4fake/6pmhM/2/

Суть в чем. Я получаю класс, а хочу иметь уже созданный на его основе объект, и мы возвращаемся к все той же проблеме со скобками вокруг функции.

Как видите то, что вы назвали «культом Карго» на самом деле помогло избежать фатальной ошибки. Я не говорю, что я прав, вставляя скобки лишний раз. Просто в данном примере они действительно нужны. Вы бы банально проверили, прежде чем утверждать, что «Они там не нужны»
Ох блин, я понял. Да, надо внимательнее смотреть на код.

Но употреблять слово «перестраховаться» по отношению к коду (а не логике) — это неправильно.
У меня на прошлой работе один чувак умудрялся писать код типа такого:

var q = parseInt(incoming, 10);
console.log(q);
q = parseInt(q, 10);


Чтоб уж точно отпарсилось!
Гхм… Я чего-то не понимаю? View.extend? в models?

app.models.page = new (Backbone.View.extend({

Вернее было назвать app.classes. Просто нужно все это где-то хранить, не захламляя namespace. Так уж вышло, что пока писал назвал models, даже внимания не обратил.
Код у вас во вьюхах ужасный. Зачем использовать data-аттрибуты для хранения данных, которые вы храните в модели? Почему не используете delegateEvents для обработки событий вьюхи?

Посмотрите хороший скринкаст (peepcode).
С delegateEvents верно, я ошибся. Тут это примером служить не может.

Зачем использовать data-аттрибуты для хранения данных, которые вы храните в модели?

Именно потому, что delegateEvents не использовал. Как мне привязать модель к dom? Выбрал самый банальный способ
Например, в view Note вместо .data('rowId') можно использовать this.model.get('id'), а вместо .find('input').val() можно было при создании инпута запомнить его и лишний раз не бегать по дереву.

Вообще вся прелесть Backbone.View в том, что объект привязан в определенному элементу DOM, при этом четко знаешь, что есть внутри, и через делегирование можно поставить нужные обработчики.

Да, вы несомненно правы. Чуть позже поправлю статью.
>Или же нужно банально связаться с сервером — а как это сделать? Все отсылают к Backbone.sync, а примеров почему-то никто не предоставляет.

Позволю себе высказать предположение, что примеров никто не предоставляет потому, что реализация функции Backbone.sync представляет какую либо сложность только для джуниор программистов. Для более менее опытного программиста реализовать бэкбон.синк задача на 15 минут.
Во-первых, я выразился ясно:
Считайте предыдущее предложение одной из основных причин написания данной заметки. Если вы с ним не согласны — дальше можно не читать.

Эта заметка именно для начинающих.

Во-вторых, вы не правы. Нельзя только по себе судить. Мне например это не показалось таким банальным. Вставить запрос легко, но где уверенность в том, что все будет нормально подхвачено? Нужно как минимум не раз проверить с разными объектами + нужно связать все это в кучу. Даже те паттерны, которые кажутся кому-то очевидными обычно где-то описаны
Зачем было писать Backbone.sync с нуля, а не использовать стандарный, с REST интерфейсом или допилить стандартную функцию под свои нужды(напр., прерывае предыдущего запроса)? Я плохо знаком с backbone, но с sync немного повозился, когда хотел отсылать не весь объект, а только измененные свойства, и на первый взгляд ваше решение гораздо менее гибкое.
Сравниваю с примером из туториала: здесь продвинутый парсинг из-за того, что нет интерфейса REST, и сервер выдаёт не JSON. В принципе, на многих фреймворках уже есть такие интерфейсы, запускаются очень легко.

Было бы очень ценный материал, если бы вы сделали редактор в броузере, как на translated.by/
Но за старания плюс поставил.
Сервер выдает JSON, просто REST не всегда удобен. Мне например нужно попутно отсылать состояние (просто строка) + сообщение об ошибке (если нужно). Если вы подскажите, как это сделать со стандартной реализацией — буду очень благодарен
>> Мне например нужно попутно отсылать состояние (просто строка) + сообщение об ошибке (если нужно).

Если единоразово — в методы save и fetch можно передавать хэш с настройками для jQuery.ajax:

model.save({}, {data: {state: 1}});
model.fetch({data: {state: 2}});


Можно переопределить метод sync для конкретной модели или коллекции:

var someModelData = {data: {state: 1}};
 
var SomeModel = Backbone.Model.extend({
    …
    sync: function(method, model, options) {
        var myOptions = options;
 
        if (method == 'read') {
            myOptions = _.extend(someModelData, myOptions);
        }
 
        Backbone.sync.call(this, method, model, myOptions);
    }
});


Ну и наконец, можно расширить Backbone.sync, а не переписать полностью:

var someData = {data: {state: 1}};
var oldSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
    var myOptions = options;
 
    if (method == 'read') {
        myOptions = _.extend(someData, myOptions);
    }
 
    return oldSync(method, model, myOptions);
};
Вы не совсем поняли. Передать данные на сервер элементарно. Как получить состояние с сервера? Оба ваших примера для этого не подходят
Ок, каюсь :)
К чему тогда относиться ваше «как это сделать со стандартной реализацией»?
Вот я и имею ввиду, как передать дополнительные данные при синхронизации? Например код ошибки. Потому и написал свой велосипед
Вы все правильно поняли. «Стандартная реализация» дополнительных действий при синхронизации с сервером — переопределить / переписать Backbone.sync.
Только сделали вы это немного варварски.

Более правильно — добавить нужную логику, а не полностью переписывать все, что не устраивает, например:
var SomeModel = Backbone.Model.extend({
    …
    sync: function(method, model, options) {
        var myOptions = options;
 
        if (method == 'create') {
            myOptions.success = function(resp, status, xhr) {
                if (resp.has_error) {
                    console.log('Error', resp);
                    return;
                }
 
                return options.success(resp, status, xhr);
            };
        }
 
        Backbone.sync.call(this, method, model, myOptions);
    }
});
Нашел время внимательней посмотреть на скрипт, не могу понять зачем так часто используются события, даже если вызываются они только внутри класса, например, «list:reload» в app.models.page?

Довольно сильно путают навзвания, кроме упомянутого app.models:
app.models.note = (Backbone.Model.extend({...
app.models.Note = (Backbone.View.extend({...

После создания классов идет внезапное создание объектов:
app.models.notes = new (Backbone.Collection.extend({...
app.models.page = new (Backbone.View.extend({...

Вся работа с backbone после document.ready, хотя описать классы можно заранее, а после загрузки страницы создать объект page.
Классы-то можно создать заранее, это не слишком важно в данном случае. А названия — вы действительно считаете, что это в данном примере важно?

События использовать очень удобно, иногда гораздо удобнее чем просто методы. У меня есть два рабочих проекта, где нужно, допустим, обновлять список. При обновлении списка нужно также подгрузить дополнительные данные + обновить некоторые модели и т.д. (ну логика такая). Через триггеры это выходит прозрачно, просто вешаем обработчики.
> Классы-то можно создать заранее, это не слишком важно в данном случае. А названия — вы действительно считаете, что это в данном примере важно?
Важно, важно не путать читателей и самого себя, что у вас получилось отлично.

> Через триггеры это выходит прозрачно, просто вешаем обработчики.
Только такой код слабо читабелен, в вашем случае внешний апи(события) выходит тесно связан со внутренним устройством.

Заметил еще большой косяк, при добавлении записи/изменении перезагружается весь список, что крайне не глупо для примера.

З. Ы. shuffle списка на стороне сервера совершенно непонятно к чему и сбивает с толку.
Довольно интересный момент, в доке особо не уточняется, но если у модели дефолтное значение id = 0, то проверка isNew() будет давать false(в js null != 0), а при сохранении всегда будет посылаться update/PUT запрос, чтобы для новых элементов был create/POST запрос, надо не задавать значение id в defaults.

Основываясь на этом, можно оставить id = 0 и убрать из синка костыль:
// Сливаем методы дубовым способом
var method = (method=='update'||method=='create')?'save':method;

т. к. всегда будет посылаться update, заодно убрать явный вызов с аргументом model.url(method)

Вместо хардкорного запиливания в sync отдачи вложенного объекта:
options.success(data.rows?data.rows:data);
стоит использовать метод parse(resp, xhr) доступный для моделей и коллекций.

После чего вспомним, что Backbone.sync возвращает xhr, который можно использовать для обрыва предыдущего соединения, тип запроса, метод и тип запроса можно подставлять через опции…
Only those users with full accounts are able to leave comments. Log in, please.

Articles