7

TL;DR:我需要设置一个默认值以显示在 select2 字段上,通过敲除绑定,但 select2 绑定不断将我的 viewmodel 值覆盖为“”而不是接受该值。

这些成分

我正在使用以下内容:

  • 淘汰赛JS
  • 在输入字段上选择 2
  • 自定义敲除绑定到 select2
  • 作为我的视图模型上的 Start() 方法的一部分加载对象(发票)的 ajax 调用。

目标

  • 加载我的值作为初始视图模型Start()函数的一部分
  • 在加载发票时将 select2 默认值绑定到我的 VM 的值。
  • 允许用户在选择时选择其他选项
    • 由于我们降低 select2 值的方式,默认值也将包含在 select2 选项中,因此无需

问题

  • 如果我从空白表单开始,Select2 会完全正常工作。它从下拉列表等的 Ajax 调用中加载我的值。
  • 但是,当我加载要显示的发票时,未在 select2 控件上设置 viewmodel 值。
    • 看起来 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"/>
4

2 回答 2

1

不确定我是否正确理解了这个问题,起初我在自定义绑定的更新部分看到了可能的问题:

update: function (element, valueAccessor) {
  //added next row to update value
  $(element).val(ko.utils.unwrapObservable(valueAccessor()));

  $(element).trigger("change");
}
于 2013-11-12T15:52:53.650 回答
1

我让它工作了,我认为不同之处在于 init 有一个选择

<input type="hidden" class=""
    data-bind="value: observedValue, select2: --your options--">

这是我的:

init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
        $(element).select2('destroy');
      });

      select2 = ko.utils.unwrapObservable(allBindings().select2);

  $(element).select2(select2);
},
于 2015-06-23T20:48:13.533 回答