Javascript 敲除JS设置选项Value破坏我的代码

Javascript 敲除JS设置选项Value破坏我的代码,javascript,jquery,knockout.js,Javascript,Jquery,Knockout.js,下面的代码已简化,请参见fiddle: 基本上,我是在数据绑定下设置设备名称,但是我还需要指定发送到数据库的optionsValue,但是当我设置它时,显示数据绑定是空的 <script id="extItems" type="text/html"> <tr> <td data-bind="text: device() && device().name"></td> </tr> </s

下面的代码已简化,请参见fiddle:

基本上,我是在数据绑定下设置设备名称,但是我还需要指定发送到数据库的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=新函数(){
var self=这个;
window.viewModel=self;
self.list=ko.observearray();
self.pageSize=ko.可观察(10);
self.pageIndex=ko.可观察(0);
self.selectedItem=ko.observable();
self.extQty=ko.observable();
self.devices=ko.observearray();
self.addressList=ko.observearray(['addressList']);
self.availableDevices=ko.computed(函数(){
var usedQuantities={};//对于每个设备id,存储使用的数量
self.list().forEach(函数(项){
var device=item.device();
如果(设备){
使用数量[device.id]=1+(使用数量[device.id]| | 0);
}
});
返回self.devices().filter(函数(设备){
var usedQuantity=usedquanties[device.id]| | 0;
返回设备数量>使用数量;
});
});
//需要此项将项目的选定设备添加回其设备选项,
//并维持设备的原始秩序
self.devicesForItem=函数(项){
var availableDevices=self.availableDevices();
返回self.devices().filter(函数(设备){
返回设备===item.device()| | availableDevices.indexOf(设备)!=-1;
});
}
self.edit=功能(项目){
if($('#extMngForm').valid(){
self.selectedItem(项目);
}
};
self.cancel=函数(){
self.selectedItem(空);
};
self.add=函数(){
if($('#extMngForm').valid(){
var newItem=newextension();
self.list.push(newItem);
self.selectedItem(新建项);
self.moveToPage(self.maxPageIndex());
}
};
self.remove=功能(项目){
如果(确认('您确定要删除此项目吗?')){
self.list.remove(项目);
if(self.pageIndex()>self.maxPageIndex()){
self.moveToPage(self.maxPageIndex());
}
}
$('.error').hide();
};
self.save=函数(){
if($('#extMngForm').valid(){
self.selectedItem(空);
};
};
self.templateouse=函数(项){
返回self.selectedItem()==item?'editExts':'extItems';
};
self.pagedList=ko.dependenttobservable(函数(){
var size=self.pageSize();
var start=self.pageIndex()*大小;
返回self.list.slice(开始,开始+大小);
});
self.maxPageIndex=ko.dependentObservable(函数(){
返回Math.ceil(self.list().length/self.pageSize())-1;
});
self.previousPage=函数(){
if(self.pageIndex()>0){
self.pageIndex(self.pageIndex()-1);
}
};
self.nextPage=函数(){
if(self.pageIndex()对于(i=0;i当您使用
optionsValue
时,KO会将属性值写入您与
value
绑定的任何内容。因此,它现在将使用id而不是对象填充值

有两种方法可以解决这种情况,即您需要值(用于发送到DB)和对象(用于绑定UI的其他部分)

一个非常典型的解决方案是在对象上创建一个计算的可观察对象,该对象接受当前选定的对象并返回id

因此,在您的
扩展中
可以执行以下操作:

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);
然后移除
选项value
并将
值绑定到
设备。asObject

在本例中,我添加了
asObject
子observable,因此当您将其转换为JSON时,它将消失(
ko.toJSON
)发送到服务器。此技术唯一棘手的部分是,如果要从服务器加载现有数据,则需要使用选项中的适当选项填充
asObject

以下是一个示例:

我使用的另一个选项是继续使用
optionsValue
,但随后创建一个自定义绑定,在一个单独的可观察对象中跟踪该对象。这里有一个自定义绑定,它为任何与
绑定的对象创建一个
子可观察对象。这样,您就不必一次搞乱它了在您的视图模型中

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

此处示例:

我刚刚注意到您的脚本破坏了我的availableDevices功能。一旦数量超过foreach中使用的数量,它应该删除该选项。有什么想法吗?
//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);
    }
};