簡體   English   中英

Knockout.js映射並將大數據集添加到ko.observableArray

[英]Knockout.js Mapping and adding large dataset to ko.observableArray

有許多使用底層數組將大型數據集添加到ko.observableArray的示例,例如:

ko.observableArray.fn.pushAll = function(valuesToPush) {
var underlyingArray = this();
this.valueWillMutate();
ko.utils.arrayPushAll(underlyingArray, valuesToPush);
this.valueHasMutated();
return this;  //optional
};

用這種方式做的問題是我失去了可觀察的東西。 當我使用chrome並在調試器中暫停時,我將在數組中獲取值,而不是在函數c()中觀察到的換行。 我還必須觀察許多這些變量。

我發現有效的方法如下:

var model = @Html.Raw(Json.Encode(Model));
vm.POs = ko.mapping.fromJS(model.POs);

問題是這很慢。 如何使用基礎數組進行添加,然后將可觀察的換行添加到每個變量而又不存在性能問題?

這是更多代碼:

var vm = {
    POs: ko.observableArray([]),

    headersWithAccounting: ko.observableArray([
        {header_name: "DATE CREATED", property: "DATE_CREATED", state: ko.observable('')},
        {header_name: "DATE ISSUED", property: "DATE_ISSUED", state: ko.observable('')},
        {header_name: "USER CREATED", property: "NAME_USER", state: ko.observable('')},
        {header_name: "PO NUMBER", property: "NO_PO", state: ko.observable('')},
        {header_name: "ORDER STATUS", property: "NAME_STATUS", state: ko.observable('')},
        {header_name: "VENDOR", property: "NAME_VENDOR", state: ko.observable('')},
        {header_name: "TOTAL COST", property: "COST_TOTAL", state: ko.observable('')},
        {header_name: "CTU", property: "ID_CTU", state: ko.observable('')},
        {header_name: "ACCOUNTING CODE", property: "ACCOUNTING_CODE_NAME", state: ko.observable('')},
        {header_name: "CLOSE ORDER", property: "ACCOUNTING", state: ko.observable('')}
    ])
};

function PO() {
var self = this;

self.ID_ORDER = ko.observable();
self.DATE_CREATED = ko.observable();
self.DATE_ISSUED = ko.observable();
self.NAME_STATUS = ko.observable();
self.NAME_VENDOR = ko.observable();
self.NAME_USER = ko.observable();
self.COST_TOTAL = ko.observable();
self.ACCOUNTING_CODE_NAME = ko.observable();
self.ACCOUNTING_CODE_ID = ko.observable();
self.NO_PO = ko.observable();
self.SHOWDETAILS = ko.observable(0);
self.ID_TYPE = ko.observable(0);
self.DESCRIPTION = ko.observable('');
self.FILES = ko.observableArray();
self.POParts = ko.observableArray();
self.ACCOUNTING = ko.observable(0);
self.ID_CTU = ko.observable(0);
self.ACCOUNTING.subscribe(function(val) {
    if (vm.avoidCloseOrder() == 0) {
        $.ajax({
            type: "POST",
            url: '@Url.Action("AccountingCloseOrder", "Report")',
            dataType: 'JSON',
            data: {
                orderId: self.ID_ORDER()
            },
            success: function(msg) {
                if (msg != 'Good') {
                    window.location.href = msg;
                }
            },
            error: function (err) {
                alert("Error closing order, please try again");
            }
        });
    }
});
self.ACCOUNTING_CODE_ID.subscribe(function(val) {
    if (vm.avoidCloseOrder() == 0) {
        $.ajax({
            type: "POST",
            url: '@Url.Action("AccountingCodeChange", "Report")',
            dataType: 'JSON',
            data: {
                orderId: self.ID_ORDER(),
                accountingCodeId: self.ACCOUNTING_CODE_ID()
            },
            success: function(msg) {
            },
            error: function (err) {
                alert("Error closing order, please try again");
            }
        });
     }
  });
}

function POPart() {
    var self = this;

    self.CATEGORY = ko.observable();
    self.SUBCATEGORY = ko.observable();
    self.DESCRIPTION = ko.observable();
    self.PARTNO = ko.observable();
    self.QTY_ORDERED = ko.observable();
    self.QTY_RECEIVED = ko.observable();
    self.COST = ko.observable();
}

function FILE() {
    var self = this;

    self.LOCATION = ko.observable();
}

現在問題出在帶有剔除綁定的剃須刀代碼中:

<div class="row">
    <div class="col-md-12">
        <div data-bind="foreach:POs">
            <table class="table-responsive">
                <thead data-bind="if: $index() == 0 || ($index() > 0 && vm.POs()[$index()-1].SHOWDETAILS() == 1)">
                    <tr data-bind="foreach:vm.headersWithAccounting">
                        <th>
                            <span data-bind="click:$root.sortPOs.bind(property), text:header_name" style="cursor:pointer"></span><i data-bind="css: state"></i>
                        </th>
                    </tr>
                </thead>
                <tbody class="clickabletbody">
                    <tr>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:DATE_CREATED"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:DATE_ISSUED"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_USER"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NO_PO"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_STATUS"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:NAME_VENDOR"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:COST_TOTAL"></div>
                        </td>
                        <td data-bind="click:$parent.showDetailsFor">
                            <div data-bind="text:ID_CTU"></div>
                        </td>
                        <td>
                            @Html.DropDownList("ddlVendor", new SelectList(Model.ACCOUNTING_CODE_SELECTLIST, "Value", "Text"), "--Select Accounting Code--", new { @class = "form-control", data_bind = "value:ACCOUNTING_CODE_ID" })
                        </td>
                        <td>
                            <input type="checkbox" style="height:30px; width: 30px;" data-bind="checked:ACCOUNTING, enable:(NAME_STATUS() == 'ACCOUNTING' || NAME_STATUS() == 'CLOSED')" />  //PROBLEM RIGHT HERE!!!!
                        </td>
                    </tr>
                </tbody>
            </table>
            <table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
                <!-- ko if:(ID_TYPE() == 2 || ID_TYPE() == 3) -->
                <thead>
                    <tr>
                        <th>
                            DESCRIPTION
                        </th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>
                            <div data-bind="text:DESCRIPTION"></div>
                        </td>
                    </tr>
                </tbody>
                <!-- /ko -->
                <!-- ko if:(ID_TYPE() == 1) -->
                <thead>
                    <tr>
                        <th>
                            CATEGORY
                        </th>
                        <th>
                            SUBCATEGORY
                        </th>
                        <th>
                            DESCRIPTION
                        </th>
                        <th>
                            PART NO
                        </th>
                        <th>
                            QTY ORDERED
                        </th>
                        <th>
                            QTY RECEIVED
                        </th>
                        <th>
                            COST
                        </th>
                    </tr>
                </thead>
                <tbody data-bind="foreach:POParts">
                    <tr>
                        <td>
                            <div data-bind="text:CATEGORY"></div>
                        </td>
                        <td>
                            <div data-bind="text:SUBCATEGORY"></div>
                        </td>
                        <td>
                            <div data-bind="text:DESCRIPTION"></div>
                        </td>
                        <td>
                            <div data-bind="text:PARTNO"></div>
                        </td>
                        <td>
                            <div data-bind="text:QTY_ORDERED"></div>
                        </td>
                        <td>
                            <div data-bind="text:QTY_RECEIVED"></div>
                        </td>
                        <td>
                            <div data-bind="text:COST"></div>
                        </td>
                    </tr>
                </tbody>
                <!-- /ko -->
            </table>
            <table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
                <thead>
                    <tr>
                        <th>
                            Files
                        </th>
                    </tr>
                </thead>
                <tbody data-bind="foreach:FILES">
                    <tr>
                        <td>
                            <a data-bind="attr: {href: LOCATION, target: '_blank'}" class="btn btn-primary btn-md">Download File</a>
                        </td>
                    </tr>
                </tbody>
            </table>
            <div data-bind="if:SHOWDETAILS"><hr /></div>
        </div>
        <!-- /ko -->
    </div>
</div>

問題出在復選框上,Chrome控制台顯示錯誤:knockout-3.4.0.js:72未捕獲的TypeError:無法處理綁定“啟用:function(){返回(NAME_STATUS()=='ACCOUNTING'|| NAME_STATUS() =='CLOSED')}“消息:NAME_STATUS不是函數

這是因為在該值中,它不再是具有剔除綁定的函數,它只是一個值,因此,它不是函數,並且此錯誤是正確的。 我迷路了,因為使用基礎數組僅推送javascript值,並且未映射可觀察的函數。

當前使用可觀察對象映射200個條目大約需要10秒鍾,如果您問我,這是非常荒謬的。 當我有1000+時會發生什么。 即使我只加載其中的50個並使用ajax收集其余信息,但每次獲得更多數據時,它都會滯后頁面幾秒鍾,直到全部加載。 不確定如何解決此問題。

編輯:

我剛好有一個AHA時刻,並解決了丟失綁定問題。 現在大約需要4秒來處理232個條目。 仍然想更快地獲得它,但是這就是我所做的改變。

function PO(data) {
    var self = this;

    self.ID_ORDER = ko.observable(data.ID_ORDER);
    self.DATE_CREATED = ko.observable(data.DATE_CREATED);
    self.DATE_ISSUED = ko.observable(data.DATE_ISSUED);
    self.NAME_STATUS = ko.observable(data.NAME_STATUS);
    self.NAME_VENDOR = ko.observable(data.NAME_VENDOR);
    self.NAME_USER = ko.observable(data.NAME_USER);
    self.COST_TOTAL = ko.observable(data.COST_TOTAL);
    self.ACCOUNTING_CODE_NAME = ko.observable(data.ACCOUNTING_CODE_NAME);
    self.ACCOUNTING_CODE_ID = ko.observable(data.ACCOUNTING_CODE_ID);
    self.NO_PO = ko.observable(data.NO_PO);
    self.SHOWDETAILS = ko.observable(0);
    self.ID_TYPE = ko.observable(data.ID_TYPE);
    self.DESCRIPTION = ko.observable(data.DESCRIPTION);

    self.FILES = ko.observableArray();

    if (data.FILES != null) {
        for (var i = 0; i < data.FILES.length; i++) {
            self.FILES.push(new FILE(data.FILES[i]));
        }
    }

    self.POParts = ko.observableArray();

    if (data.POParts != null) {
        for (var i = 0; i < data.POParts.length; i++) {
            self.POParts.push(new POPart(data.POParts[i]));
        }
    }

    self.ACCOUNTING = ko.observable(data.ACCOUNTING);

    self.ID_CTU = ko.observable(data.ID_CTU);

    self.ACCOUNTING.subscribe(function(val) {
        if (vm.avoidCloseOrder() == 0) {
            $.ajax({
                type: "POST",
                url: '@Url.Action("AccountingCloseOrder", "Report")',
                dataType: 'JSON',
                data: {
                    orderId: self.ID_ORDER()
                },
                success: function(msg) {
                    if (msg != 'Good') {
                        window.location.href = msg;
                    }
                },
                error: function (err) {
                    alert("Error closing order, please try again");
                }
            });
        }
    });

    self.ACCOUNTING_CODE_ID.subscribe(function(val) {
        if (vm.avoidCloseOrder() == 0) {
            $.ajax({
                type: "POST",
                url: '@Url.Action("AccountingCodeChange", "Report")',
                dataType: 'JSON',
                data: {
                    orderId: self.ID_ORDER(),
                    accountingCodeId: self.ACCOUNTING_CODE_ID()
                },
                success: function(msg) {
                },
                error: function (err) {
                    alert("Error closing order, please try again");
                }
            });
        }
    });
}

function POPart(data) {
    var self = this;

    self.CATEGORY = ko.observable(data.CATEGORY);
    self.SUBCATEGORY = ko.observable(data.SUBCATEGORY);
    self.DESCRIPTION = ko.observable(data.DESCRIPTION);
    self.PARTNO = ko.observable(data.PARTNO);
    self.QTY_ORDERED = ko.observable(data.QTY_ORDERED);
    self.QTY_RECEIVED = ko.observable(data.QTY_RECEIVED);
    self.COST = ko.observable(data.COST);
}

function FILE(data) {
    var self = this;

    self.LOCATION = ko.observable(data.LOCATION);
}

和推送功能:

ko.observableArray.fn.pushAll = function(valuesToPush)
{
    var underlyingArray = this();
    this.valueWillMutate();
    ko.utils.arrayForEach(valuesToPush, function(item) {
        underlyingArray.push(new PO(item));
    });
    this.valueHasMutated();
    return this;
}

有什么想法可以使速度快於4秒嗎?

我沒有真正理解“我松開約束”的意思。 這可能是調試器的偽像(它向您顯示了可觀察的值)。

我也可能是“這個”問題。

我得到了有效的代碼段(在填充數組時可以使用單擊綁定)

 var elementVM = (function () { function elementVM(message) { this.myText = ko.observable(message); } elementVM.prototype.changeText = function () { this.myText(this.myText() + " changed"); }; return elementVM; }()); var myVM = (function() { var getText = function(count) { return "My Text " + (count); }; var myObservableArray = ko.observableArray([new elementVM(getText(0))]); return function() { this.myArray = myObservableArray; myVM.prototype.populate = function() { myObservableArray.valueWillMutate(); for(var i = 1; i <= 1000; ++i) { myObservableArray().push(new elementVM("My Text " + i)); } myObservableArray.valueHasMutated(); }; }; }()); var vm = new myVM(); ko.applyBindings(vm); setTimeout(function() { var start = new Date(); vm.populate(); var stop = new Date(); document.getElementById("pushAll").innerHTML = "pushallTiming: " + (stop - start); }, 1000); 
 li { list-style: none; border: 1px solid black; width: auto; text-align: center; } #pushAll { background-color: red; width: auto; text-align: center; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <div id="pushAll"></div> <ul data-bind="template: { name: 'my-template', foreach: myArray }"></ul> <script type="text/html" id="my-template"> <li data-bind="text: myText, click: changeText"></li> </script> 

實際復制到陣列所需的時間少於1秒。 它是valueHasMutated()函數,需要花費幾秒鍾,而多數民眾贊成在這只是KO的一部分。 我很高興它花了很長時間將數據復制到數組中。 我將嘗試僅對50個條目進行分頁,這應有助於DOM更快地加載。 謝謝大家的回應。

暫無
暫無

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

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