我用DurandalJS创建了一个显示特定数据的Web应用程序。这些数据通过BreezeJS收集,并从DurandalJS框架的激活函数中调用。
当我第一次进入页面A时,所有数据都正确加载。当我通过页面A上的链接转到页面B,然后通过链接从页面B返回到页面A时,我可以看到数据加载到我的KnockoutJS observablearays中,但它没有显示!
当页面上有多条可观察到的光线时,比如A1、B2和C3,在第一次加载时,当我在Web应用程序上冲浪并返回到具有可观察到的光线的特定页面时,它们都被正确加载,一个时刻A1和C3被加载,而B2没有!另一个时刻A1、B2和C3没有显示。这是非常随机的!
当我按CTRL + F5的时候,所有的东西都被正确加载了。这和DurandalJS的框架有什么关系吗?有人知道如何修复这个问题吗?
到目前为止,我尝试了以下方法:
- 使用延迟
- 使用deactivate可以正确地清理属性,以便在activate中填充它们
目前为止还没有。
库的版本:
- 敲除JS:2.3.0
- 微风JS:1.4.0
- 持续时间JS:1.2.0
这些是我所包含的库的当前版本。它们是最近更新的,希望这能解决问题,但它没有。
下面是我的数据服务,它是一个Singleton:
var DataserviceClass = (function () {
function DataserviceClass() {
this._isSaving = false;
this.suspendItemSave = false;
this.ds = new breeze.DataService({
serviceName: "api/data",
hasServerMetadata: true
});
this.manager = new breeze.EntityManager({dataService: this.ds});
this.metadataStore = this.manager.metadataStore;
this.entityQuery = new breeze.EntityQuery();
this.getMetadataStore = function () {
return this.metadataStore;
};
this.getExportData = function() {
return this.manager.exportEntities();
};
this.getAllRows = function (functionName, expand) {
if (expand == null || expand == undefined) {
this.entityQuery = breeze.EntityQuery.from(functionName);
} else {
this.entityQuery = breeze.EntityQuery.from(functionName).
expand(expand);
}
return this.manager.executeQuery(this.entityQuery);
};
this.getSpecificID = function (functionName, idName, id) {
this.entityQuery = breeze.EntityQuery.from(functionName).where(idName, "==", id);
return this.manager.executeQuery(this.entityQuery);
};
this.createT = function (initialValues, entity) {
return this.manager.createEntity(entity, initialValues);
};
this.saveChanges = function (suppressLogIfNothingToSave) {
if (this.manager.hasChanges()) {
if (this._isSaving) {
setTimeout(this.saveChanges, 50);
return;
}
return this.manager.saveChanges().then(this.saveSucceeded).fail(this.saveFailed).fin(this.saveFinished);
} else if (!suppressLogIfNothingToSave) {
}
};
this.saveSucceeded = function (saveResult) {
this._isSaving = false;
};
this.saveFailed = function (error) {
};
this.saveFinished = function () {
this._isSaving = false;
};
}
var instance;
return {
getInstance: function() {
if (instance == null) {
instance = new DataserviceClass();
instance.constructor = null;
}
return instance;
}
};
})();
在一个页面上像估计它的调用如下,这是视图模型:
define(function (require) {
var router = require('durandal/plugins/router'),
app = require('durandal/app'),
system = require('durandal/system'),
addmemo = require('viewmodels/modals/addMemo'),
container = require('viewmodels/modals/container'),
memo = require('viewmodels/modals/memo'),
dataservice = require('services/dataservice'),
logger = require('services/logger'),
addRepairOrderLine = require('viewmodels/modals/addRepairOrderLine'),
repairorderline = require('viewmodels/modals/RepairOrderLine'),
customerModal = require('viewmodels/modals/customer'),
currentLoggedInEmployee = ko.observable(),
memos = ko.observableArray([]),
deferred = $.Deferred(),
repairorderlines = ko.observableArray([]),
tasksToMonitor = [],
isLoading = ko.observable(false),
suspendItemSave = false,
rightParameters = true,
notDone = true,
hourscost = ko.observable(0.0),
materialcost = ko.observable(0.0),
grandtotal = ko.observable(0.0),
currentRepairOrderID = -1,
currentOrderID = -1,
currentOrder = ko.observable(),
currentRepairOrder = ko.observable(null),
currentContainerID = -1,
currentCustomer = ko.observable(null),
currentBillingCustomer = ko.observable(null),
currentContainer = ko.observable(null),
showElementFade = function(elem) { if (elem.nodeType === 1) $(elem).hide().slideDown(); },
hideElementFade = function(elem) { if (elem.nodeType === 1) $(elem).slideUp(function() { $(elem).remove(); }); };
//This function is called ones, only when the page hasn't loaded yet!
function init() {
dataservice = DataserviceClass.getInstance();
dataservice.getSpecificID('Employees', 'EmployeeID', 1).then(function (data) {
currentLoggedInEmployee = data.results[0];
}).fail(function(data) {
logger.logError('Error fetching the current logged in employee!', null, null, true);
});
}
init();
return {
displayName: 'Estimating page',
router: router,
currentCustomer: currentCustomer,
currentContainer: currentContainer,
currentRepairOrder: currentRepairOrder,
currentBillingCustomer: currentBillingCustomer,
memos: memos,
repairorderlines: repairorderlines,
isLoading: isLoading,
hourscost: hourscost,
materialcost: materialcost,
grandtotal: grandtotal,
activate: function (Context) {
currentRepairOrder(null);
currentBillingCustomer(null);
rightParameters = true;
//also need to check if ids exist in DB!!
if (!Context.hasOwnProperty("orderid") || isNaN(Context.orderid) ||
!Context.hasOwnProperty("repairorderid") || isNaN(Context.repairorderid)) {
rightParameters = false;
system.log('Not all the right parameters!');
router.navigateTo('#/error'); //eventueel parameters meegeven!
return;
}
//set id's
currentRepairOrderID = Context.repairorderid;
currentOrderID = Context.orderid;
tasksToMonitor = []; //empty the task function
breeze.EntityQuery.from("Orders")
.where("OrderID", "==", parseInt(Context.orderid))
.expand("Customer, Customer.PostCountry, Customer.VisitCountry, Container, Container.ContainerManufacturer, Container.ContainerType, Container.Owner")
.using(dataservice.manager)
.execute().then(function (data) {
if (data.results.length < 1) {
system.log('Not all the right parameters!');
rightParameters = false;
router.navigateTo('#/error'); //eventueel parameters meegeven!
return;
}
//extendItem(data.results[0]);
currentOrder(data.results[0]);
var customer = data.results[0].Customer();
//extendItem(customer);
currentCustomer(customer);
var container = data.results[0].Container();
//extendItem(container);
currentContainer(container);
}).fail(function (data) {
logger.logError('Error fetching the current Order!', null, null, true);
}).fin(function() {
});
//In the future this will be calling the order 2
breeze.EntityQuery.from("RepairOrders")
.where("RepairOrderID", "==", parseInt(Context.repairorderid))
.expand("BillingCustomer, BillingCustomer.PostCountry, BillingCustomer.VisitCountry")
.using(dataservice.manager)
.execute().then(function (data) {
currentRepairOrder(data.results[0]);
currentBillingCustomer(data.results[0].BillingCustomer());
}).fail(function (data) {
logger.logError('Error fetching current repairorder!', null, null, true);
}).fin(function() {
//first set the value to true (loading done)
//Call the global function to check each process
tasksToMonitor[0][1] = true;
checkTasks();
});
//by adding this if statements the data is only loaded if it hasn't been loaded yet!
//voor nu alle memos van alle medewerkers, later alleen die van betreffende?
if (memos._latestValue.length == 0) {
breeze.EntityQuery.from("Memos")
.where("RepairOrderID", "==", parseInt(Context.repairorderid))
//.expand("Customer, Container, Container.ContainerManufacturer, Container.ContainerType")
.expand("Employee")
.using(dataservice.manager)
.execute().then(function (data) {
data.results.forEach(function (item) {
extendItem(item);
memos.push(new memo(item));
});
system.log("Initialization succesfull!");
logger.logSuccess('Initialization succesfull', null, 'estimatepage', true);
}).fail(function (data) {
logger.logError('Error fetching memos!', null, null, true);
}).fin(function() {
tasksToMonitor[1][1] = true;
checkTasks();
});
}
if (repairorderlines._latestValue.length == 0) {
breeze.EntityQuery.from("RepairOrderLines")
.where("RepairOrderID", "==", parseInt(Context.repairorderid))
.expand("Customer")
.using(dataservice.manager)
.execute().then(function (data) {
data.results.forEach(function (item) {
extendItem(item);
repairorderlines.push(new repairorderline(item));
});
updateFinance();
//
}).fail(function (data) {
logger.logError('Error fetching repairorderlines!', null, null, true);
}).fin(function() {
tasksToMonitor[2][1] = true;
checkTasks();
// deferred.resolve();
});
}
logger.log("Estimating page started!", null, "estimagepage", true);
return deferred.promise();
//return;
},
canDeactivate: function () {
if (rightParameters && notDone) {
return app.showMessage('Are you sure you want to leave this page and stop estimating?', 'Navigate', ['Yes', 'No']);
} else {
return true;
}
},
deactivate: function() {
//remove everything here! I mean remove the data in the models! Everything is already saved ;)
memos.removeAll();
repairorderlines.removeAll();
currentRepairOrderID = -1;
currentOrderID = -1;
currentOrder(null);
currentRepairOrder(null);
currentContainerID = -1;
currentCustomer(null);
currentBillingCustomer(null);
currentContainer(null);
},
showCustomerModal: function(selectedCustomer,element) {
app.showModal(new customerModal(selectedCustomer)).then(function () {
}).fail(function() {
});
},
showContainerModal: function() {
app.showModal(new container(currentContainer, currentOrder())).then(function (result) {
}).fail(function(result) {
});
},
cancelEstimation: function() {
app.showMessage('Do you want to delete this estimation?', 'Delete estimate', ['Yes', 'No']).then(function (resultMessageBox) {
if (resultMessageBox == "Yes") {
}
//else if no the user just clicked OK and everything is saved
});
},
selectedRepairOrderLine: function (selectedRepairOrderLine, element) {
app.showModal(selectedRepairOrderLine).then(function (result) {
if (result) {
app.showMessage('Do you want to delete this RepairOrderLine?', 'Delete RepairOrderLine', ['Yes', 'No']).then(function (resultMessageBox) {
if (resultMessageBox == "Yes") {
repairorderlines.remove(selectedRepairOrderLine);
selectedRepairOrderLine.RepairOrderLineEntity._latestValue.entityAspect.setDeleted();
dataservice.saveChanges();
updateFinance(); //dont remove this one its called !
logger.logSuccess('Repairline deleted successfully', null, null, true);
}
//else if, no the user just clicked OK and everything is saved so also updatefinance is called a couple of line further
});
}
updateFinance(); //But we must update the finance because things could have been changed!
}).fail(function () {
logger.logError('Something went wrong selecting the memo!', null, 'estimatepage', true);
});
},
selectedMemo: function (selectedMemo, element) {
app.showMessage('Do you want to delete this memo?', 'Delete memo', ['Yes', 'No']).then(function (resultMessageBox) {
if (resultMessageBox == "Yes") {
memos.remove(selectedMemo);
selectedMemo.MemoEntity._latestValue.entityAspect.setDeleted();
dataservice.saveChanges();
}
//else if no the user just clicked OK and everything is saved
}).fail(function () {
logger.logError('Something went wrong selecting the memo!', null, 'estimatepage', true);
});
},
};
});
这是它附带的视图:
<div class="row-fluid">
<div class="span6">
<!-- Estimate Information -->
<!-- Estimate HEADER -->
<div class="fiftypx" data-bind='with: currentContainer'>
<span class="main_title">ESTIMATE</span>
<span class="main_container_number" data-bind="text: ContainerNumber"></span>
</div>
<!-- Estimate Propertys -->
<div class="row-fluid">
<div class="span6">
<fieldset>
<div class="estimate_info" data-bind="with: currentContainer">
<span class="estimatepage_info_text">container number</span>
<div data-bind="" class="estimate_info_DIV">
<span data-bind="text: ContainerNumber"></span>
</div>
</div>
<div style="clear: both;"></div>
<div class="estimate_info" data-bind="with: currentBillingCustomer">
<span class="estimatepage_info_text">billing customer</span>
<div data-bind="click: $parent.showCustomerModal" class="estimate_info_DIV">
<span data-bind="text: Name"></span>
</div>
<button class="flatButtonSmall" data-bind="click: $parent.showCustomerModal">›</button>
</div>
<div style="clear: both;"></div>
<div class="estimate_info" data-bind='with: currentContainer'>
<span class="estimatepage_info_text">equipment</span>
<div data-bind="click: $parent.showContainerModal" class="estimate_info_DIV">
<span data-bind="text: ContainerNumber"></span>
</div>
<button class="flatButtonSmall" data-bind="click: $parent.showContainerModal">›</button>
</div>
<div style="clear: both;"></div>
</fieldset>
</div>
<div class="span6">
<fieldset>
<!--<legend></legend> Deze niet toevoegen uitlijning is dan niet goed!-->
<div class="estimate_info" data-bind="with: currentRepairOrder">
<span class="estimatepage_info_text">repair order</span>
<div class="estimate_info_DIV">
<span data-bind="text: RepairOrderID"></span>
</div>
</div>
<div style="clear: both;"></div>
<div class="estimate_info" data-bind='with: currentCustomer'>
<span class="estimatepage_info_text">relation</span>
<div data-bind="click: $parent.showCustomerModal" class="estimate_info_DIV">
<span data-bind="text: Name"></span>
</div>
<button class="flatButtonSmall" data-bind="click: $parent.showCustomerModal">›</button>
</div>
<div style="clear: both;"></div>
<div class="estimate_info" data-bind="with: currentRepairOrder">
<span class="estimatepage_info_text">creation date</span>
<div class="estimate_info_DIV">
<span data-bind="text: Created().getDate() + '-' + (Created().getMonth() + 1) + '-' + Created().getFullYear()"></span>
</div>
</div>
<div style="clear: both;"></div>
</fieldset>
</div>
</div>
</div>
<div class="span6">
<!-- Memo's -->
<div class="fiftypx">
<span class="main_title">MEMO'S</span>
<button class="newButton" data-bind="click: addMemo">NEW</button>
<button data-bind="click: doneEstimating" style="width: 130px;float: right;margin-right: 25px;" class="flatButtonBig" data-bind="">DONE</button>
<div style="clear: both;"></div>
<div>
<div class="loader" data-bind="css: { active: isLoading }">
<i class="icon-spinner icon-2x icon-spin"></i>
</div>
</div>
</div>
<div id="memosTable">
<table class="table" style="margin-left: -25px;">
<thead>
<tr>
<th></th><th>date / user</th><th>memo</th><th></th>
</tr>
</thead>
<tbody data-bind="visible: memos().length > 0, foreach: memos">
<tr class="rowStyleFront">
<td style="width:25px;"></td>
<td style="width: 115px;">
<!-- date and user -->
<!-- text: MemoEntity._latestValue.CreationDate -->
<span class="upperSpan" data-bind="">Datum</span>
<div style="clear: both;"></div>
<span class="lowerSpan" data-bind="text: MemoEntity._latestValue.Employee().Username()"></span>
</td>
<td style="width: 300px;">
<!-- memo -->
<span style="display: inline; background-color: #f4931D; color: #FFFFFF; padding-right: 7px; padding-left: 5px;" class="upperSpan" data-bind="textToUpperCase: MemoEntity._latestValue.Type"></span>
<div style="clear: both;"></div>
<span style="margin-top: 20px; width: inherit;" class="lowerSpan" data-bind="text: MemoEntity._latestValue.Description"></span>
</td>
<td style="width: 50px;"><button data-bind="click: $parent.selectedMemo" style="float: right;" class="flatButtonBig" data-bind="">X</button></td>
</tr>
</tbody>
<tbody data-bind="visible: memos().length == 0">
<tr class="rowStyleFront">
<td style="width:25px;"></td>
<td colspan="3">You haven't made any memo's yet.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span6">
<!-- Add new repairline button and text -->
<div class="fiftypx">
<span class="main_title">REPAIRLINES</span>
<button class="newButton" data-bind="click: addRepairline">NEW</button>
</div>
</div>
<div class="span6" style="line-height: 50px;">
<!-- totals! -->
<div class="row-fluid">
<div class="span4">Hours cost: <span style="font-size: 16px;" data-bind="text: hourscost()"></span></div>
<div class="span4">Materials: <span style="font-size: 16px;" data-bind="text: materialcost()"></span></div>
<div class="span4">Total: <span style="font-size: 16px;" data-bind="text: grandtotal()"></span></div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<!-- Table with all repairlines -->
<table class="table" style="margin-left: -25px;">
<thead>
<tr>
<th></th>
<th>Description</th>
<th></th>
<th>Code</th>
<th>Mat</th>
<th>LOC</th>
<th>Rep</th>
<th>DAM</th>
<th>Customer</th>
<th>IsAgreement</th>
<th>Qty</th>
<th>Hours</th>
<th>Tariff</th>
<th>Costs</th>
<th>Lessee</th>
<th>Authorized</th>
<th>DoRepair</th>
<th><!-- Button --></th> <!-- 17 rijen -->
</tr>
</thead>
<tbody data-bind="visible: repairorderlines().length > 0, foreach: repairorderlines">
<tr class="rowStyleFront">
<td style="width:25px;"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.Description"></td>
<td></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.InternalCode"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.MaterialCode"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.LocationCode"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.RepairCode"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.DamageCode"></td>
<td style="text-align: left;" data-bind="click: $parent.selectedRepairOrderLine, text: RepairOrderLineEntity._latestValue.Customer().Name()"></td>
<td><input type="checkbox" data-bind="checked: RepairOrderLineEntity._latestValue.IsAgreement"/></td>
<td data-bind="click: $parent.selectedRepairOrderLine, numericText: RepairOrderLineEntity._latestValue.Quantity"></td>
<td data-bind="click: $parent.selectedRepairOrderLine, numericText: RepairOrderLineEntity._latestValue.Hours"></td>
<td data-bind="click: $parent.selectedRepairOrderLine, numericText: RepairOrderLineEntity._latestValue.Tariff"></td>
<td data-bind="click: $parent.selectedRepairOrderLine, numericText: RepairOrderLineEntity._latestValue.Costs"></td>
<td data-bind="click: $parent.selectedRepairOrderLine">-</td>
<td><input type="checkbox" data-bind="checked: RepairOrderLineEntity._latestValue.IsAuthorized"/></td>
<td><input type="checkbox" data-bind="checked: RepairOrderLineEntity._latestValue.DoRepair"/></td>
<td style="width: 50px;"><button class="flatButtonBig" data-bind="click: $parent.selectedRepairOrderLine">›</button></td>
</tr>
</tbody>
<tbody data-bind="visible: repairorderlines().length == 0">
<tr class="rowStyleFront">
<td style="width:25px;"></td>
<td colspan="16">You haven't made any repairlines yet.</td>
</tr>
</tbody>
</table>
</div>
</div>
4条答案
按热度按时间xghobddn1#
视图模型:
wqnecbli2#
编辑
好吧,我会尽可能地帮助你,并指出一些事情的过程中-
1.在Visual Studio或您选择的编辑器中打开您的项目,然后执行“Find”,搜索整个项目,以及任何您在视图模型或视图中看到“latestValue”的地方,或者除了敲除库之外的任何地方,您需要删除它。如果您需要KO Observable或ObservableArray中的值,请使用getter函数-
应该是
我知道我之前已经回答了你的一个问题,并建议这样做,我回去仔细检查了一下,但你真的需要这样做,你正在通过使用_latestValue绕过Knockout的核心功能。
1.我检查了您创建的几个ID可观察对象,似乎您创建了它们并将它们设置为-1,但从未使用它们-将它们全部删除,如果您需要currentContainer或其他可观察对象的ID,只需调用currentContainer().id()。
1.当您定义observableArray时,不需要将它设为相等nothing,也不需要在停用时呼叫removeAll()。
第一次定义变量-
将变量设置为空-
因此,当您停用时,只需将其设置为等于nothing,而不是使用removeAll()。
这看起来工作量很大,但实际上并不是,我有一种感觉,我们可能会发现为什么您的视图模型在第二次加载过程中只加载了一半的数据。
"看这里"
在一些地方,您将可观测量设置为等于data.results,这很好,但让我们尝试将它们稍微清理一下(我不是说数组data.results中的第一项上没有名为Customer的函数,但如果没有,这将解决问题)-
让我们把它调整到-
您的停用功能
原始答案
排除Breeze的问题-如果您的Knockout可观察性充满数据,则您的查询可能会如预期般运作。
消除Knockout问题-如果视图模型填充了数据,这是一个好兆头。如果视图本身存在绑定问题,您可以尝试以下几种方法-
1.查看控制台-是否有任何数据绑定中断?
1.您的视图是否处理在声明绑定后可能加载数据的情况?
在尝试显示数据之前,这将等待,直到加载了可观察数组-
这不会-
但是你可以调试它或者防止绑定被破坏-
排除杜兰达尔的问题-
Durandal的框架相当稳定,您是否发现了一个其他人都没有发现的bug,这是非常值得怀疑的。更有可能的是,您第一次访问该页面时所做的事情与第二次访问该页面时所做的事情不同。没有代码,我们无法帮助进一步调试它。
关于Durandal的一个关键注意事项-如果您的视图模型是一个Singleton对象,并且您依赖于某些数据来 * 始终 * 存在,那么您应该考虑使用构造函数模块。更多信息@http://durandaljs.com/documentation/Creating-A-Module/
fnx2tebb3#
我发现了文件:DurandalJS框架的viewModelBinder.js部分负责处理绑定。
调试时,我看到绑定的值。然后我看到有些值有时确实是空的。所以当它们被绑定时是空的。但是当我输入一个全新的值时,它们不会被重新绑定。
我该如何解决这个问题?只有当所有的异步调用都准备好了,并且neccassery属性都填充好了,页面才会被绑定?
eeq64g8w4#
是的,我修好了:)
我的解释是:每个breeze函数都有一个jQuery延迟对象,每个页面也有一个全局对象。在activate函数中,我调用了jQuery的when函数,所有的函数都在其中执行。
如果有任何其他(更好的)方法,请让我现在!我检查了Chrome的控制台,我看到日志都是在绑定之前执行的!这就是问题所在!