TL;DR:我需要设置一个默认值以显示在 select2 字段上,通过敲除绑定,但 select2 绑定不断将我的 viewmodel 值覆盖为“”而不是接受该值。
这些成分
我正在使用以下内容:
- 淘汰赛JS
- 在输入字段上选择 2
- 自定义敲除绑定到 select2
- 作为我的视图模型上的 Start() 方法的一部分加载对象(发票)的 ajax 调用。
目标
- 加载我的值作为初始视图模型
Start()
函数的一部分 - 在加载发票时将 select2 默认值绑定到我的 VM 的值。
- 允许用户在选择时选择其他选项
- 由于我们降低 select2 值的方式,默认值也将包含在 select2 选项中,因此无需
问题
- 如果我从空白表单开始,Select2 会完全正常工作。它从下拉列表等的 Ajax 调用中加载我的值。
- 但是,当我加载要显示的发票时,未在 select2 控件上设置 viewmodel 值。
- 看起来 select2 控件实际上加载了数据并
""
在加载时覆盖了我的视图模型的值,因为尚未选择一个值——而不是让我根据我的绑定值显示一个默认项。
- 看起来 select2 控件实际上加载了数据并
到目前为止关于试图解决它的想法
我将调查所有这些:
- 我可能没有正确使用敲除绑定来允许不属于其值的默认元素选择。
- 如果有一种方法可以验证 select2 框是否已加载,然后触发元素更新,那也很好。
编码
文件加载
$(document).ready(function () {
'use strict';
console.log("creating viewmodel");
vm = new invoiceDetailsPage.ViewModel();
vm.Start();
console.log("applying bindings");
ko.applyBindings(vm);
});
invoiceDetailsPage NameSpace(删除了一些不相关的部分)
var invoiceDetailsPage = invoiceDetailsPage || {
InvoiceDetailItem: function () {
'use strict';
var self = this;
self.DatePayable = new Date();
self.Fees = 0.00;
self.Costs = 0.00;
self.Adjustments = ko.observable();
self.AdjustmentNote = ko.observable();
self.Total = ko.computed(function () {
});
self.hasAdjustments = ko.computed(function () {
});
},
Invoice: function (invoiceID, documentTypeID, firmID, invoiceNumber, invoicePeriod, datePayable, privateComment, statusID, vendorFirmID) {
'use strict';
var self = this;
self.TypeID = ko.observable(documentTypeID);
self.PrivateComment = ko.observable(privateComment);
self.Status = ko.observable(statusID);
self.FirmID = ko.observable(firmID);
self.VendorFirmID = ko.observable(vendorFirmID);
self.InvoicePeriod = ko.observable(invoicePeriod);
self.DatePayable = ko.observable(datePayable);
self.InvoiceNumbers = ko.observable(invoiceNumber);
self.DetailItems = ko.observableArray([]);
self.isFinalized = ko.computed(function () {
//finalized if it has the appropriate status (anything except)
});
self.hasPrivateComments = ko.computed(function () {
// if self.privatecomment isn't null or empty, true
});
self.TotalFees = ko.computed(function () {
//foreach item in detailitems, sum of fees.
});
self.TotalCosts = ko.computed(function () {
//foreach item in detailitems, sum of Costs.
});
self.TotalAdjustments = ko.computed(function () {
//foreach item in detailitems, sum of adjustments.
});
self.GrandTotal = ko.computed(function () {
//foreach item in detailitems, sum of totals.
});
},
LoadInvoice: function (clientSiteID, invoiceID, callbackFunction, errorFunction) {
'use strict';
var self = this;
self.clientSiteID = clientSiteID;
self.invoiceID = invoiceID;
$.ajax({
url: '/api/DefenseInvoice/GetDefenseInvoice?ClientSiteID=' + self.clientSiteID + "&InvoiceID=" + invoiceID,
type: 'GET',
processData: false,
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: null,
success: function (data) {
console.log(data);
callbackFunction(data);
},
error: function (jqXHR, textStatus, errorThrown) {
errorFunction(jqXHR, textStatus, errorThrown);
}
});
},
ViewModel: function () {
'use strict';
var self = this;
self.InvoiceLoaded = ko.observable();
self.Invoice = ko.observable(new invoiceDetailsPage.Invoice()); // load blank invoice first
self.clientSiteID = -1;
self.invoiceID = -1;
self.SaveInvoiceDetails = function () {
// can only save the details prior to approval / rejection
// should update only general invoice fields, not private comments or adjustments
};
self.LoadInvoice = function() {
self.InvoiceLoaded(false);
invoiceDetailsPage.LoadInvoice(self.clientSiteID, self.invoiceID, function(result) {
//success
vm.Invoice(new invoiceDetailsPage.Invoice(
result.InvoiceInfo.DefenseInvoiceID,
result.InvoiceDocumentTypeID,
result.InvoiceInfo.FirmID,
result.InvoiceInfo.InvoiceNumber,
result.InvoiceInfo.InvoicePeriod,
result.InvoiceInfo.DatePayable,
result.InvoiceInfo.PrivateComment,
result.InvoiceInfo.StatusID,
result.InvoiceInfo.VendorFirmID
));
self.InvoiceLoaded(true);
}, function() {
//error
toastr.error("We're sorry, but an error occurred while trying to load the invoice. Please contact support or refresh the page to try again.", "Invoice Approval");
console.log("LoadInvoice -- ERROR");
console.log(" error: " + errorThrown);
toastr.clear(notifier);
});
};
self.Start = function () {
self.LoadInvoice();
};
},
utils: {
GetSelect2Options: function (placeholder, url) {
'use strict';
var options = {
allowClear: false,
placeholder: placeholder,
query: function (query) {
var dto = {
query: query.term,
filters: {
ClientSiteID: Number(vm.clientSiteID)
}
};
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(dto),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
query.callback(msg);
}
});
}
};
return options;
}
}
};
我们正在使用的淘汰赛绑定
ko.bindingHandlers.select2 = {
init: function (element, valueAccessor, allBindingsAccessor) {
var obj = valueAccessor(),
allBindings = allBindingsAccessor(),
lookupKey = allBindings.lookupKey;
$(element).select2(obj);
if (lookupKey) {
var value = ko.utils.unwrapObservable(allBindings.value);
$(element).select2('data', ko.utils.arrayFirst(obj.data.results, function (item) {
return item[lookupKey] === value;
}));
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).select2('destroy');
});
},
update: function (element) {
$(element).trigger('change');
}
};
HTML 元素及其绑定
<input type="text" id="ddlInvoiceType" placeholder="Invoice Type" class="select2-container" data-bind="select2: invoiceDetailsPage.utils.GetSelect2Options('Invoice Type', '/api/DefenseInvoiceType/Post'), value: Invoice().TypeID"/>