[英]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.