Коллекция Backbone обновить все элементы - PullRequest
2 голосов
/ 16 февраля 2012

У меня проблемы с обновлением коллекции или, точнее, представления коллекции после обновления всех моделей на сервере. Вот мой сценарий:

  1. У меня есть коллекция вопросов, полученных с сервера. Каждый вопрос имеет атрибут позиции, поэтому я могу управлять порядком в списке и сохранять его на сервере с соответствующим порядком.

  2. У меня есть представление для каждого отдельного элемента списка и представление с более глобальной областью действия, которое генерирует каждый элемент списка и обновляет коллекцию. По сути, я использовал пример из книги О'Рейли «Веб-приложения Javascript», который очень напоминает знаменитое учебное пособие по аннотациям Todo, которое можно найти здесь: http://documentcloud.github.com/backbone/docs/todos.html Таким образом, структура почти идентична, за исключением нескольких пользовательских моделей. Всё отлично работает.

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

    window.QuestionView = Backbone.View.extend({
    
    el: $("#content"),
    events : {
        'sortupdate ol#questions': 'sortStuff'
    },
    
    initialize: function(collection) {
        this.collection = new QuestionsList;
    
        _.bindAll(this, 'addOne', 'addAll', 'render', 'addNewItem', 'addItem');
        this.collection.bind('add', this.addNewItem);
        this.collection.bind('all', this.render);
        this.collection.bind('reset', this.addAll);
        this.collection.fetch({
            data: { quiz_id: $qid },
            processData:true
        });
    },
    
    render: function() {},
    
    sortStuff: function() {
    
        $this = this;
        $.ajax({
            url: "/hq/reorder/",
            type: "POST",
            data: $("#questions").sortable("serialize")+"&id="+$qid,
            dataType: 'json',
            success: function(data) {
    
            }
        });
    },
    
    addItem: function() {
        this.collection.add({title: 'New title goes here'});
        return false;
    },
    
    addNewItem: function(question) {
        var view = new ItemView({model: question, parent: this});
        var element = view.render().el;
        this.$("#questions").prepend(element);
        $that = this;
        $(view.render().el).addClass('new');
    },
    
    addOne: function(question) {
      var view = new ItemView({model: question, parent: this});
      this.$("#questions").prepend(view.render().el);
    },
    
    addAll: function() {
      this.collection.each(this.addOne);
      return false;
    }
    

    * *} тысячи двадцать-одина); * ** тысячи двадцать-два * тысячи двадцать-три

Итак, мой вопрос: что мне делать в случае успеха: чтобы иметь возможность обновлять каждую маленькую модель отдельно, чтобы она обновляла цифры в правильном порядке? Может быть, какой-то _.each на коллекции? Или, может быть, какое-то глобальное обновление представления для всей коллекции?

Также мой успех: функция (данные) возвращает новый заказ в виде списка (или объекта JSON) с сервера. может быть, я смогу повторно использовать этот порядок, чтобы установить для каждой модели новое значение, не делая ненужного вызова fetch () на сервере каждый раз, когда меняется порядок?

EDIT:

Мне, наконец, удалось заставить его работать со сбросом, очистив представление и повторно загрузив новую коллекцию. Возможно, это не лучший способ сделать это, так как есть дополнительный вызов на сервер с fetch () ..

 sortStuff: function() {

        $this = this;
        $.ajax({
            url: "/hq/reorder/",
            type: "POST",
            data: $("#questions").sortable("serialize")+"&id="+$qid,
            dataType: 'json',
            success: function(data) {
                $this.rerender();
            }
        });


    },

    rerender: function() {

        this.collection.fetch({
            data: { quiz_id: $qid },
            processData:true
        });
        $("#questions").html("");
        this.collection.reset();
        this.addAll();
    },

Ответы [ 2 ]

2 голосов
/ 17 февраля 2012

Я думаю, что ваш подход должен состоять из двух отдельных шагов: 1) С одной стороны вы обновляете данные на сервере 2) С другой стороны, вы обновляете коллекцию на стороне клиента

Итак, вы в порядке на шаге 1, вы сказали, что это работает.

На шаге 2 вы можете воспользоваться программированием, управляемым событиями. Логика такова:

  1. ВЫ ТОЛЬКО ДОБАВЛЯЕТЕ ОДИН ЭЛЕМЕНТ В КОЛЛЕКЦИЮ (collection.add (модель) запускает событие add).
  2. В коллекции вы прослушиваете событие add. Когда вы его ловите, вы снова сортируете свою коллекцию (collection.sort запускает событие reset)
  3. В вашем представлении для списка (questionView в вашем случае) вы прослушиваете событие сброса коллекции, и после его запуска вы повторно визуализируете свое представление

Пример кода:

1) QuestionView: удален addItem и упрощен addNewItem (он не должен отображаться)

 window.QuestionView = Backbone.View.extend({
 el: $("#content"),
 events : {
     'sortupdate ol#questions': 'sortStuff'
 },

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
 },

 render: function() {},

 sortStuff: function() {

     $this = this;
     $.ajax({
         url: "/hq/reorder/",
         type: "POST",
         data: $("#questions").sortable("serialize")+"&id="+$qid,
         dataType: 'json',
         success: function(data) {

         }
     });
 },

 //METHOD addItem REMOVED!!!


 addNewItem: function(question) {
     this.collection.add({title: 'New title goes here'}); //***IT FIRES AN ADD EVENT
     },

 addOne: function(question) {
   var view = new ItemView({model: question, parent: this});
   this.$("#questions").prepend(view.render().el);
 },

 addAll: function() {
   this.collection.each(this.addOne);
   return false;
 }

});

2) коллекция перехватывает событие добавления и сортирует (запускает событие сброса) вы всегда можете обработать это в QuestionView, ваша функция инициализации становится.

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
     //ADD THIS*****
     this.collection.on('add', function(){
         this.collection.sort();
     });
 },

3) третий шаг уже сделан, вы просто заново визуализируете представление

Лучше всего, если вы сортируете элементы в своей коллекции, определяя новую функцию «компаратор», которая использует атрибут «позиция» вашего списка

что-то вроде (в QuestionView)

this.collection.comparator: function(){
   return this.collection.get("position");
}

так, чтобы элементы были упорядочены по позиции СТОРОНА КЛИЕНТА

** EDIT ** Функция инициализации изменена. Выборка используется вместо «сортировки», что бесполезно, если атрибут «позиция» каждого элемента в коллекции не обновляется.

 initialize: function(collection) {
     this.collection = new QuestionsList;
     _.bindAll(this, 'addOne', 'addAll', 'addNewItem');
     this.collection.bind('add', this.addNewItem);
     this.collection.bind('reset', this.addAll);
     this.collection.fetch({
     data: { quiz_id: $qid },
     processData:true
     });
     //ADD THIS*****
     this.collection.on('add', function(){
         this.collection.fetch();
     });
0 голосов
/ 16 февраля 2012

Вы должны сделать Questions.reset(data);, однако вы должны сообщить ajax, что ответом является json:

sortStuff: function() {
   $.ajax({
     url: '/order',
     data: $("ol#questions").sortable('serialize'),
     dataType: 'json',
     success: function(data) {
        // now data is an object
        Questions.reset(data);
     });
   });
}

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

EDIT:

Хорошо, теперь с кодом я вижу, чего вы пытаетесь достичь, и ваша логика ошибочна. Вам не следует ждать вызова Ajax, чтобы вернуть новый заказ. Лучше, если вы обновите заказ на стороне клиента, а затем сохраните модель.

Вот пример jsfiddle: http://jsfiddle.net/b75px/

Объедините это с позвоночником, и у вас должно получиться:

Заметьте , что я просто догадываюсь, как вы организовали вопросы. Если у вас есть какие-либо другие проблемы, обновите свой вопрос с более подробной информацией.

events: {
    'sortstart ol#questions': 'startSortingQuestions',
    'sortupdate ol#questions': 'updateQuestions'
},
startSortingQuestions: function(event, ui) {
    this.beforeIndex = ui.item.index();
},
updateQuestions: function(event, ui) {
    var before = this.beforeIndex,
        after = ui.item.index();

    // now that you have the index change, all you have to do is set the new index
    // and save them to the database
    this.collection.at(before).set({ index: after; }).save();
    this.collection.at(after).set({ index: before; }).save();

    // passing silent: true because sort invokes the reset event,
    // and we don't need to redraw anything
    this.collection.sort({ silent: true });

    /* or maybe an even better approach: 
    var beforeModel = this.collection.at(before);
    var toSwapModel = this.collection.at(after);

    this.collection.remove(beforeModel);
    this.collection.remove(toSwapModel);
    this.collection.add(beforeModel, { at: after, silent: true });
    this.collection.add(toSwapModel, { at: before, silent: true });

    note that I have no idea on how your database is structured, so my guess is
    every question has it's index so you know it's order
    therefore, you should still update the model's index field or whatever it is you're doing
    */
}
...