我正在开发一个包含多个区域的 SPA,这些区域可以动态加载到 div (id=#main) 中。
为了实现这一点,我使用 SammyJS 进行路由,并使用 knockoutjs 进行绑定。特定子页面的加载就像$('#main').load('pages/subpage.html');
子页面包含两个切换的 div(主/详细模式)一样。
数据被加载.getJSON('data.php',....)
到创建的淘汰模型中的 observableArray 中。
一切正常,第一次加载页面时会显示项目列表。
当我选择一个项目并使用后退按钮切换回列表时,它只是调用self.list()
我将 currentUser 设置为的位置null
,而不是包含用户数组项目的正确列表,它显示纯掩码,没有考虑任何数据绑定(显示了两个 div)。
错误:尽管数据仍然存在,但不再显示项目列表(已使用 进行检查console.log(...)
。数据绝对可用且正确,但不知何故绑定未更新...
这里是特定的代码示例:
<div data-bind="load: loadData()">
<div id="userlist" class="row" data-bind="visible: !currentUser()">
<h1 class="lead">Please select a User ...</h1>
<div class="twelve columns">
<table class="striped rounded" data-bind="visible: users().length > 0">
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody data-bind="foreach: users">
<tr data-bind="click: $parent.show">
<td><span data-bind="text: id"></span></td>
<td><span data-bind="text: firstname"></span></td>
<td><span data-bind="text: lastname"></span></td>
<td>
<a class="default btn" data-bind="click: $parent.show">show</a>
<a class="default btn" data-bind="click: $parent.delete">delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!--
User Details
-->
<div id="userdetails" class="row" data-bind="with: currentUser">
<div class="breadcrumb"><span data-bind="click: $root.list">Userdetails ></span> <span data-bind="text: name"></span></div>
<div class="twelve columns">
<table class="striped rounded">
<tbody>
<form></form>
<tr class="field">
<td><label class="inline" for="userFirstName">Firstname</label></td>
<td style="width:100%"><input class="normal text input" name="userFirstName" type="text" placeholder="First name" data-bind="value: firstname"></td>
</tr>
<tr class="field">
<td><label class="inline" for="userlastname">Firstname</label></td>
<td style="width:100%"><input class="normal text input" name="userlastname" type="text" placeholder="Family name" data-bind="value: lastname"></td>
</tr>
</tbody>
</table>
<div>
<div class="medium btn default"><a href="#" data-bind="click: $root.save">save</a></div>
<span> </span>
<div class="medium btn default"><a href="#" data-bind="click: $root.delete">delete</a></div>
<div class="medium btn default"><a href="#/users">back</a></div>
</div>
</div>
</div>
<!--
Knockout Models
-->
<script>
ko.validation.init({ grouping : { deep: true, observable: true } });
ko.validation.rules.pattern.message = 'Invalid.';
ko.validation.configure({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
parseInputAttributes: true,
//messageTemplate: null,
decorateElement: true
});
var userModel = function(){
var self = this;
self.id = ko.observable();
self.firstname = ko.observable().extend({required: { message: 'First name is a required field.' }});
self.lastname = ko.observable().extend({required: { message: 'Last name is a required field.' }});
return self;
};
var userData = function(){
var self = this;
self.users = ko.observableArray([]);
self.currentUser = ko.observable();
self.viewMode = ko.observable('list');
self.list = function(){
self.currentUser(null);
self.viewMode('list');
location.hash = '/users';
console.log('list '+ self.users().length+ ' users');
console.log(ko.toJSON(self.users()));
};
self.show = function(item){
self.currentUser(item);
self.viewMode('details');
location.hash = '/users/' + item.id();
console.log('show user:'+ko.toJSON(item));
};
self.loadData = function(){
//fetch existing data from database
console.log('loaddata - User');
//self.users = ko.observableArray([]);
$.getJSON("pages/user.php", function(data) {
data.forEach(function(item){
var newModel = new userModel();
newModel.id(item['id']);
newModel.firstname(item['firstname']);
newModel.lastname(item['lastname']);
self.users.push(newModel);
});
});
}
}
if (!_userData){
var _userData = new userData();
ko.applyBindings(_userData);
}
</script>