/ 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".
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);
}
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
:-)
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.
- to dodaje modele, które są w odpowiedzi, ale nie w istniejącej kolekcji.
- to usuwa modele, które znajdują się w istniejącej kolekcji, ale nie w odpowiedzi.
- 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";
}
};
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; });
},
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