这是一个有些人为的例子,但我相信它能够解决这个问题。
让我们说我有一个骨干车系列。对于集合,我想要一个名为isValid的属性。我希望其他对象能够绑定到isValid并在isValid更改时触发函数。集合isValid属性将根据集合中的模型进行更改。
例如,如果所有车门都锁定在每辆车上,那么isValid应该更改为true。当isValid更改时,应触发绑定到isValid change事件的所有函数。
我的问题是,如何创建一个具有与模型属性类似的可绑定属性的集合?
这是我想要工作的代码。
var Car = Backbone.Model.extend({});
var Cars = Backbone.Collection.extend({
model: Car,
url: "Cars",
isValid: false, //Here's the property that I want bindable
//but do not know how to accomplish this.
});
var cars = new Cars();
//Call a function when cars.isValid changes
cars.bind("change:isValid", carsIsValidChanged, cars)
//Not sure if this what the function would look like
//but would need access to cars.isValid or just the car collection
function carsIsValidChanged(isValid){
console.log(isValid);
}
<小时/> 更新
请在下面查看我的完整解决方案。
答案 0 :(得分:5)
因此,没有“内置”方式来响应Collection上的属性更改,因为实际上没有支持的方式(我知道)在集合上具有属性。但是,我估计它仍然完全可能。 (未经测试,但应该相当接近)
var Car = Backbone.Model.extend({});
var Cars = Backbone.Collection.extend({
model: Car,
url: "Cars",
initialize: function() {
var self = this;
this.isValid = false;
this.bind('add', function() {
var curValid = true;
self.each(function(car) {
if(car.get('is_locked') != true) {
curValid = false;
}
});
if(curValid != self.isValid) {
self.isValid = curValid;
self.trigger('change:isValid', self.isValid, self);
}
});
}
});
// instantiate a new Cars collection
var cars = new Cars();
function carsIsValidChanged(isValid){
console.log(isValid);
}
//Call a function when cars.isValid changes
cars.bind("change:isValid", carsIsValidChanged)
一个注意事项:您不希望isValid:列为属性,就像您建模或网址一样。这似乎使骨干很奇怪,你的isValid可能会跨越集合的所有实例。最好将它们定义为初始化程序,然后每次实例化该集合时,您都可以通过this.isValid正确地访问isValid的实例。
答案 1 :(得分:5)
你可以使用这样的东西;
Backbone.Collection.prototype.bindableProperty = function (key, val) {
var self = this;
Object.defineProperty(this, key, {
configurable: false,
get: function () { return val; },
set: function (v) {
val = v;
self.trigger('change:'+key, val)
}
});
};
只需这样做即可添加属性;
var Cars = Backbone.Collection.extend({
model: Car,
url: "Cars",
initialize: function () {
this.bindableProperty('isValid', false);
}
});
警告;旧版本的IE不支持Object.defineProperty。
答案 2 :(得分:2)
以下是我对此问题的完整解决方案: jsFiddle Complete example
@spotmat让我按正确的方向行事,但我需要添加其他功能。这里有一些需要解决的问题:
我不确定是否向一个集合中添加绑定属性是一个好主意,但这很有趣,我学到了很多东西。
var log = {};//this is for debugging
_.extend(log, Backbone.Events);
var Car = Backbone.Model.extend({});
var Cars = Backbone.Collection.extend({
model: Car,
url: "scripts/data/Cars.json",
initialize: function () {
var _this = this;
this.isValid = false; //user should bind to "change:isValid"
this._isPending = false; //This is so that
this.bind("add", this.modelAdded, this);
this.bind("reset", this.modelsAdded, this);
if (this.length > 0) {
//Model passed in though the constructor will not be binded
//so call modelsAdded
this.modelsAdded(this);
}
},
modelsAdded: function (collection) {
this._isPending = true
log.trigger("log", ["modelsAdded: " + collection.length]);
collection.each(this.modelAdded, this); //Do nut remove "this" param. It need when modelAdded gets called
this._isPending = false
this._validate();
},
modelAdded: function (model) {
log.trigger("log", ["modelAdded: " + model.get("Model") + "; IsLocked: " + model.get("IsLocked")]);
//!!!for each model added to the colleciton bind
//its IsLocked property to the collection modelIsLockedChange function
model.bind("change:IsLocked", this.modelIsLockedChanged, this);
if (this._isPending == false) {
this._validate();
}
},
modelIsLockedChanged: function (model) {
log.trigger("log", ["modelIsLockedChanged:" + model.get("Model") + "; IsLocked: " + model.get("IsLocked")]);
this._validate();
},
_validate: function () {
var isValid = true;
this.each(function (model) {
if (model.get("IsLocked") == false) {
isValid = false
}
});
if (this.isValid != isValid) {
this.isValid = isValid
cars.trigger("change:isValid", [this.isValid])
}
},
});
此视图仅用于调试目的
var Logger = Backbone.View.extend({
el: $("#output"),
initialize: function(){
log.bind("log", this.logMessage, this)
},
render: function(){
return $(this.el).html("");
},
logMessage: function(message){
$(this.el).find("ul").append("<li>" + message[0] + "</li>");
}
})
以下代码用于测试集合
var logger = new Logger();
log.bind("log", function(message){
console.log(message[0]);
});
var carsData = [
{ "Model": "Chevy Camero", "Year": 1982, "IsLocked": true },
{ "Model": "Ford F-150", "Year": 2011, "IsLocked": false }
]
var cars = new Cars(carsData);
cars.bind("change:isValid", function(isValid){
log.trigger("log", ["change:isValid: " + isValid]);
});
cars.add({ "Model": "Toyota Tacoma", "Year": 2006, "IsLocked": true });
cars.at(1).set({ "IsLocked": true });