/ Align = "left" / js

Staram się zachować kręgosłup.js Collection na bieżąco z tym, co dzieje się na serwerze.

Mój kod jest podobny do następującego:

var Comment = Backbone.Model.extend({});
var CommentCollection = Backbone.Collection.extend({
    model: Comment
});

var CommentView = Backbone.View.extend({ /* ... */ });
var CommentListView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'addOne', 'addAll');

        this.collection.bind('add', this.addOne);
        this.collection.bind('refresh', this.addAll);
    },
    addOne: function (item) {
        var view = new CommentView({model: item});
        $(this.el).append(view.render().el);
    },
    addAll: function () {
        this.collection.each(this.addOne);
    }
});

var comments = new CommentCollection;
setInterval(function () {
    comments.fetch();
}, 5000);

Dzieje się tak, że gdy komentarze są pobierane, refresh jest wywoływany, te same komentarze na dole CommentListView - czego oczekiwałbym po powyższym kodzie.

Chciałbym wiedzieć, jaki jest najlepszy sposób na "odświeżenie" widoku, bez utraty "lokalnego stanu".

Author: Julien, 2011-05-11

4 answers

Chcesz odświeżyć kolekcję co kilka sekund i dodać nowe komentarze. Moja sugestia to poradzenie sobie z tym problemem na Twoim zapleczu. Wyślij ostatni znacznik czasu z ostatniego komentarza i poproś serwer o deltę tylko od tej daty.

Aby to zrobić, w swojej kolekcji:

CommentCollection = Backbone.Collection.extend({
  url: function(){
    return "/comments?from_time=" + this.last().get("created_at");
  },
  comparator: function(comment){
    return comment.get("created_at");
  }
});

W Twoim backendzie odpytywaj bazę danych na podstawie parametru from_time.Twój kod klienta nie zmienia się, aby odświeżyć widok.

Jeśli nie chcesz zmienić swojego kod zaplecza z dowolnego powodu dodaj tę linię w funkcji addAll:

addAll: function(){
  $(this.el).empty();
  this.collection.each(this.addOne);
} 
 16
Author: Julien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-11 14:21:07

Lub po prostu użyj znacznie prostszego dodatku do metody fetch backbone:

this.fetch({ update: true });

Gdy dane modelu powrócą z serwera, kolekcja zostanie (efektywnie) zresetowana, chyba że przekażesz {update: true}, w którym to przypadku użyje update, aby (inteligentnie) scalić pobrane modele. - Backbone Documentation

:-)

 30
Author: Jason Stonebraker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-29 16:31:16

Kręgosłup.Kolekcja.merge ([opcje])

Bazując na powyższej odpowiedzi @Jeb, umieściłem to zachowanie w rozszerzeniu szkieletu, które można skopiować i wkleić do .plik js i dołącz do strony (po włączeniu samej biblioteki szkieletowej).

Zapewnia metodę o nazwie merge dla szkieletu.Obiekty kolekcji. Zamiast w pełni resetować istniejącą kolekcję (tak jak robi to fetch), porównuje ona odpowiedź serwera z istniejącą kolekcją i łączy ich różnice.

  1. to dodaje modele, które są w odpowiedzi, ale nie w istniejącej kolekcji.
  2. to usuwa modele, które znajdują się w istniejącej kolekcji, ale nie w odpowiedzi.
  3. wreszcie, to aktualizuje atrybuty modeli znalezionych w istniejącym zbiorze i w odpowiedzi.

Wszystkie oczekiwane zdarzenia są uruchamiane w celu dodawania, usuwania i aktualizacji modeli.

Theoptions hash pobiera success i error wywołania zwrotne, które zostaną przekazane (collection, response) jako argumenty, i zapewnia trzecią opcję wywołania zwrotnego o nazwie complete, która jest wykonywana niezależnie od sukcesu lub błędu(głównie pomocna w scenariuszach ankiet).

Uruchamia zdarzenia o nazwie "merge: success" i "merge: error".

Oto rozszerzenie:

// Backbone Collection Extensions
// ---------------

// Extend the Collection type with a "merge" method to update a collection 
// of models without doing a full reset.

Backbone.Collection.prototype.merge = function(callbacks) {
    // Make a new collection of the type of the parameter 
    // collection.
    var me = this;
    var newCollection = new me.constructor(me.models, me.options);
    this.success = function() { };
    this.error = function() { };
    this.complete = function() { };

    // Set up any callbacks that were provided
    if(callbacks != undefined) {
        if(callbacks.success != undefined) {
            me.success = callbacks.success;
        }

        if(callbacks.error != undefined) {
            me.error =  callbacks.error;
        }

        if(callbacks.complete != undefined) {
            me.complete = callbacks.complete;
        }
    }

    // Assign it the model and url of collection.
    newCollection.url = me.url;
    newCollection.model = me.model;

    // Call fetch on the new collection.
    return newCollection.fetch({
        success: function(model, response) {
            // Calc the deltas between the new and original collections.
            var modelIds = me.getIdsOfModels(me.models);
            var newModelIds = me.getIdsOfModels(newCollection.models);

            // If an activity is found in the new collection that isn't in
            // the existing one, then add it to the existing collection.
            _(newCollection.models).each(function(activity) {
                if (_.indexOf(modelIds, activity.id) == -1) { 
                    me.add(activity);
                }
            }, me);

            // If an activity in the existing collection isn't found in the
            // new one, remove it from the existing collection.
            var modelsToBeRemoved = new Array();
            _(me.models).each(function(activity) {
                if (_.indexOf(newModelIds, activity.id) == -1) {  
                    modelsToBeRemoved.push(activity);
                }
            }, me);
            if(modelsToBeRemoved.length > 0) {
                for(var i in modelsToBeRemoved) {
                    me.remove(modelsToBeRemoved[i]);
                }
            }

            // If an activity in the existing collection is found in the
            // new one, update the existing collection.
            _(me.models).each(function(activity) {
                if (_.indexOf(newModelIds, activity.id) != -1) { 
                    activity.set(newCollection.get(activity.id));  
                }
            }, me);

            me.trigger("merge:success");

            me.success(model, response);
            me.complete();
        },
        error: function(model, response) {
            me.trigger("merge:error");

            me.error(model, response);
            me.complete();
        }
    });
};

Backbone.Collection.prototype.getIdsOfModels = function(models) {
        return _(models).map(function(model) { return model.id; });
};

Prosty Scenariusz Użycia:

var MyCollection = Backbone.Collection.extend({
  ...
});
var collection = new MyCollection();
collection.merge();

Scenariusz Obsługi Błędów:

var MyCollection = Backbone.Collection.extend({
  ...
});

var collection = new MyCollection();

var jqXHR = collection.merge({
    success: function(model, response) {
        console.log("Merge succeeded...");
    },
    error: function(model, response) {
        console.log("Merge failed...");
        handleError(response);
    },
    complete: function() {
        console.log("Merge attempt complete...");
    }
});

function handleError(jqXHR) {
    console.log(jqXHR.statusText);

    // Direct the user to the login page if the session expires
    if(jqXHR.statusText == 'Unauthorized') {
        window.location.href = "/login";                        
    }
};
 8
Author: Jason Stonebraker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-02 15:12:42

Utwórz duplikat kolekcji. Fetch () it. Porównaj te dwa, aby znaleźć delty. Zastosuj je.

      /*
       * Update a collection using the changes from previous fetch,
       * but without actually performing a fetch on the target 
       * collection. 
       */
      updateUsingDeltas: function(collection) {
        // Make a new collection of the type of the parameter 
        // collection.
        var newCollection = new collection.constructor(); 

        // Assign it the model and url of collection.
        newCollection.url = collection.url;
        newCollection.model = collection.model;

        // Call fetch on the new collection.
        var that = this;
        newCollection.fetch({
          success: function() {
            // Calc the deltas between the new and original collections.
            var modelIds = that.getIdsOfModels(collection.models);
            var newModelIds = that.getIdsOfModels(newCollection.models);

            // If an activity is found in the new collection that isn't in
            // the existing one, then add it to the existing collection.
            _(newCollection.models).each(function(activity) {
              if (modelIds.indexOf(activity.id) == -1) { 
                collection.add(activity);
              }
            }, that);

            // If an activity in the existing colleciton isn't found in the
            // new one, remove it from the existing collection.
            _(collection.models).each(function(activity) {
              if (newModelIds.indexOf(activity.id) == -1) {  
                collection.remove(activity);  
              }
            }, that);

            // TODO compare the models that are found in both collections,
            // but have changed. Maybe just jsonify them and string or md5
            // compare.
          }
        });
      },

      getIdsOfModels: function(models) {
        return _(models).map(function(model) { return model.id; });
      },
 3
Author: Jeb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-04 06:12:50