2013-03-30 112 views
0

下面的代碼被簡化,看到小提琴:http://jsfiddle.net/QTUqD/7/淘汰賽JS設置optionsValue破壞我的代碼

基本上我的數據綁定設置下的設備名稱,但我也需要指定發送關閉optionsValue到數據庫,但是當我設置它時,顯示數據綁定是空的。

<script id="extItems" type="text/html"> 
    <tr> 
     <td data-bind="text: device() && device().name"></td> 
    </tr> 
</script> 

<script id="editExts" type="text/html"> 
    <tr> 
     <td> 

     <select data-bind="options: $root.devicesForItem($data), optionsText: 'name', value: device, optionsValue: 'id'"></select> 

     </td> 
    </tr> 
</script> 

window.ExtListViewModel = new function() { 
    var self = this; 
    window.viewModel = self; 

    self.list = ko.observableArray(); 

    self.pageSize = ko.observable(10); 
    self.pageIndex = ko.observable(0); 
    self.selectedItem = ko.observable(); 
    self.extQty = ko.observable(); 
    self.devices = ko.observableArray(); 
    self.addressList = ko.observableArray(['addressList']); 
    self.availableDevices = ko.computed(function() {   
     var usedQuantities = {}; // for each device id, store the used quantity 
     self.list().forEach(function(item) { 
      var device = item.device(); 
      if (device) { 
       usedQuantities[device.id] = 1 + (usedQuantities[device.id] || 0); 
      } 
     }); 

     return self.devices().filter(function(device) { 
      var usedQuantity = usedQuantities[device.id] || 0; 
      return device.qty > usedQuantity; 
     }); 
    }); 

    // need this to add back item's selected device to its device-options, 
    // and to maintain original order of devices 
    self.devicesForItem = function(item) {   
     var availableDevices = self.availableDevices(); 
     return self.devices().filter(function(device) { 
      return device === item.device() || availableDevices.indexOf(device) !== -1; 
     }); 
    } 

    self.edit = function (item) { 
     if($('#extMngForm').valid()) { 
      self.selectedItem(item); 
     } 
    }; 

    self.cancel = function() { 
     self.selectedItem(null); 
    }; 

    self.add = function() { 
     if($('#extMngForm').valid()) { 
      var newItem = new Extension(); 
      self.list.push(newItem); 
      self.selectedItem(newItem); 
      self.moveToPage(self.maxPageIndex()); 
     } 
    }; 
    self.remove = function (item) { 

      if (confirm('Are you sure you wish to delete this item?')) { 

        self.list.remove(item); 
        if (self.pageIndex() > self.maxPageIndex()) { 
         self.moveToPage(self.maxPageIndex()); 
        } 

      } 
      $('.error').hide(); 
    }; 
    self.save = function() { 
     if($('#extMngForm').valid()) { 
      self.selectedItem(null); 
     }; 
    }; 

    self.templateToUse = function (item) { 
     return self.selectedItem() === item ? 'editExts' : 'extItems'; 
    }; 

    self.pagedList = ko.dependentObservable(function() { 
     var size = self.pageSize(); 
     var start = self.pageIndex() * size; 
     return self.list.slice(start, start + size); 
    }); 
    self.maxPageIndex = ko.dependentObservable(function() { 
     return Math.ceil(self.list().length/self.pageSize()) - 1; 
    }); 
    self.previousPage = function() { 
     if (self.pageIndex() > 0) { 
      self.pageIndex(self.pageIndex() - 1); 
     } 
    }; 
    self.nextPage = function() { 
     if (self.pageIndex() < self.maxPageIndex()) { 
      self.pageIndex(self.pageIndex() + 1); 
     } 
    }; 
    self.allPages = ko.dependentObservable(function() { 
     var pages = []; 
     for (i = 0; i <= self.maxPageIndex() ; i++) { 
      pages.push({ pageNumber: (i + 1) }); 
     } 
     return pages; 
    }); 
    self.moveToPage = function (index) { 
     self.pageIndex(index); 
    }; 


}; 

ko.applyBindings(ExtListViewModel, document.getElementById('extMngForm')); 

function Extension(extension, name, email, vmpin, device, macAddress, shipTo){ 
    this.extension = ko.observable(extension); 
    this.name = ko.observable(name); 
    this.email = ko.observable(email); 
    this.vmpin = ko.observable(vmpin); 
    this.device = ko.observable(device); 
    this.macAddress = ko.observable(macAddress); 
    this.shipTo = ko.observable(shipTo); 
} 

回答

2

當您使用optionsValue,KO寫道,無論你已綁定對value的屬性值。所以,現在它會使用id而不是對象填充值。

有兩種方法可以解決這種情況,您需要值(用於發送到數據庫)和對象(用於綁定用戶界面的其他部分)。

一個非常典型的解決方案是在您的對象上創建一個計算的可觀察對象,該對象採用當前選定的對象並返回該ID。

所以,在你Extension你會做這樣的事情:

this.device = ko.computed({ 
    read: function() { 
     var device = this.device.asObject(); 
     return device && device.id; 
    }, 
    deferEvaluation: true, //deferring evaluation, as device.asObject has not been created yet 
}, this); 

//create this as a sub-observable, so it just disappears when we turn this into JSON and we are just left with the id to send to the DB 
this.device.asObject = ko.observable(device); 

然後取出optionsValue並結合valuedevice.asObject

在這種情況下,我加入了asObject子觀察到的,所以它會當你把它變成JSON(ko.toJSON)發送到服務器時,就會丟掉。關於這種技術的唯一棘手的部分是,如果您要從服務器加載現有數據,那麼您需要使用選項中的適當選項填充asObject

這裏有一個例子:http://jsfiddle.net/rniemeyer/Q3PEv/

,我是用另一種選擇是繼續使用optionsValue,但隨後創建跟蹤在一個單獨的觀察到該對象的自定義綁定。這是一個自定義綁定,創建一個asObject子可觀察值,用於與value綁定的任何值。這樣,你真的不需要在視圖模型中混淆它。

//when using optionsValue, still track the select object in a different observable 
ko.bindingHandlers.valueAsObject = { 
    init: function(element, valueAccessor, allBindingsAccessor) { 
     var value = allBindingsAccessor().value, 
      prop = valueAccessor() || 'asObject'; 

     //add an "asObject" sub-observable to the observable bound against "value" 
     if (ko.isObservable(value) && !value[prop]) { 
       value[prop] = ko.observable(); 
     } 
    }, 
    //whenever the value or options are updated, populated the "asObject" observable 
    update: function(element, valueAccessor, allBindingsAccessor) { 
     var prop = valueAccessor(), 
      all = allBindingsAccessor(), 
      options = ko.utils.unwrapObservable(all.options), 
      value = all.value, 
      key = ko.utils.unwrapObservable(value), 
      keyProp = all.optionsValue, 
      //loop through the options, find a match based on the current "value" 
      match = ko.utils.arrayFirst(options, function(option) { 
       return option[keyProp] === key; 
      }); 

     //set the "asObject" observable to our match 
     value[prop](match); 
    } 
}; 

樣品在這裏:http://jsfiddle.net/rniemeyer/E2kvM/

+0

你是驚人的。 – Stephen

+0

我只注意到你的腳本破壞了我的availableDevices函數。一旦qty超過了foreach中使用的數字,它應該刪除該選項。有任何想法嗎? – Stephen