簡體   English   中英

Backbone.js - 如何創建具有可綁定屬性的集合

[英]Backbone.js - How to create a collection that has bindable properties

這是一個人為的例子,但我相信它可以解決這個問題。

讓我們說我有一個骨干車系列。 對於集合,我想要一個名為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);
}


更新

請在下面查看我的完整解決方案。

因此,沒有“內置”方式來響應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的實例。

你可以使用這樣的東西;

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。

這是我對這個問題的完整解決方案: jsFiddle完整示例

@spotmat讓我走向正確的方向,但我需要添加其他功能。 這里有一些需要解決的問題:

  • 集合構造函數需要處理基於它的數據
  • 更新模型IsLocked屬性時,需要重新驗證集合

我不確定是否將一個綁定屬性添加到一個集合是一個好主意,但是這很有趣,我學到了很多東西。

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 });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM