根据我的viewmodel,我无法更新视图。总结我正在做的事情:我有一系列项目(AllCredentials)。项目的一个属性是“IsSelected”值(true或false)。当项的值为false(创建AllCredentials数组时的默认值)时,该项将显示在“UnselectedCredentials”列表中。当双击此列表中的项目时,“IsSelected”的值将被切换,从而使其显示在另一个“SelectedCredentials”列表中。
当我测试它时,双击时“IsSelected”值正在切换,但计算出的数组(其中2个,每个对应2个列表)没有相应地添加/删除(如当双击“UnselectedCredentials”列表中的某个项目时,“IsSelected”的值应该从false切换为true,从而将其从该列表中删除并将其添加到“SelectedCredentials”列表中。
这是我的代码:
视图模型:
var TestNWJS = TestNWJS || {};
TestNWJS.QualificationList = (function () {
//private functions
function FindUnselectedCredentials() { //function to populate UnselectedCredentials list
var filtering = ko.utils.arrayFilter(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) {
return item.IsSelected === false;
});
return filtering;
}
function FindSelectedCredentials() { //function to populate SelectedCredentials list
var filtering = ko.utils.arrayFilter(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) {
return item.IsSelected === true;
});
return filtering;
}
function CreateQualificationModel(allCredentialsList) {
TestNWJS.QualificationList.ViewModel = {};
TestNWJS.QualificationList.ViewModel.AllCredentials = ko.observableArray(allCredentialsList);
TestNWJS.QualificationList.ViewModel.UnselectedCredentials = ko.computed(FindUnselectedCredentials, this);
TestNWJS.QualificationList.ViewModel.SelectedCredentials = ko.computed(FindSelectedCredentials, this);
TestNWJS.QualificationList.ViewModel.AllCredentials.extend({ notify: 'always' });
TestNWJS.QualificationList.ViewModel.UnselectedCredentials.extend({ notify: 'always' });
TestNWJS.QualificationList.ViewModel.SelectedCredentials.extend({ notify: 'always' });
}
function toggleselected(id) {
var match = ko.utils.arrayFirst(TestNWJS.QualificationList.ViewModel.AllCredentials(), function (item) {
id = parseInt(id);
return id === item.Id;
});
match.IsSelected = !match.IsSelected;
return match;
}
//public function
return {
Init: function (allCredentialsList) {
CreateQualificationModel(allCredentialsList);
//when you select something from the dropdown this will happen.
$("select[name='QualificationFilter']").change(function (e) {
var id = $(this).val();
e.preventDefault();
var form = $(e.target).parents("form");
var url = window.location.href.substr(0, window.location.href.lastIndexOf("QualificationList") + 17)
form.attr("action", url + "?Id=" + id);
form.submit();
});
$("#UnselectedCredentialsList").live('dblclick', function (e) {
toggleselected(this.value);
});
$("#SelectedCredentialsList").live('dblclick', function (e) {
toggleselected(this.value);
});
ko.applyBindings(TestNWJS.QualificationList.ViewModel);
}
}
})();
查看:
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Available Credentials")
</td>
<td class="fieldData_td">
<select data-bind="options: UnselectedCredentials,
optionsText: 'Name',
optionsValue: 'Id'"
size="10" multiple="multiple" id="UnselectedCredentialsList"></select>
</td>
</tr>
</table>
</div>
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Selected Credentials")
</td>
<td class="fieldData_td">
<select data-bind="options: SelectedCredentials,
optionsText: 'Name',
optionsValue: 'Id'"
size="10" multiple="multiple" id="SelectedCredentialsList"></select>
</td>
</tr>
</table>
</div>
}
@section scripts {
@Scripts.Render("~/Scripts/knockout-2.2.1.js", "~/jscripts/Administration/Interfaces/QualificationList.js", "~/Scripts/knockout.mapping-latest.js")
<script type="text/javascript">
$(function () {
TestNWJS.QualificationList.Init(@Html.Raw(Model.JsonAllCredentials));
})
</script>
}
只是为了澄清一下,在页面的初始加载时,“UnselectedCredentials”列表正确显示(意味着AllCredentials数组中所有凭据的“IsSelected”值等于false(这是最初的所有内容)正在出现) 。我遇到的问题与双击触发器切换值后视图(和可能的视图模型)无法正确更新有关。
答案 0 :(得分:1)
我认为问题可能是JSON数据的初始加载。如果我没有弄错,Knockout不会自动使JSON对象的属性可观察。 observableArray仅查看在数组中添加或删除项目的时间,而不是其中的项目是否已更改。您可能需要为JSON数据编写反序列化器,或者使用构造函数创建一个Credential类(使所有属性都可观察),您可以在将它们放入可观察数组之前将JSON数据的元素提供给它们。
查看Knockout Mapping Plugin。这可能会有所帮助
我不确定你是否受到视图模型的约束,但我还建议简化一下。没有理由拥有多个数组并来回移动项目。一个更简单的实现是拥有一个数组,根据Selection属性是true还是false显示在表中。像这样:
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Available Credentials")
</td>
<td class="fieldData_td">
<table data-bind="foreach:Credentials">
<!-- ko if: !Selected -->
<tr>
<td data-bind="text><select data-bind="text: Name, $root.click: toggleSelected></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<div>
<table>
<tr>
<td class="fieldName_td">
@Html.Label("Selected Credentials")
</td>
<td class="fieldData_td">
<table data-bind="foreach:Credentials">
<!-- ko if: Selected -->
<tr>
<td data-bind="text><select data-bind="text: Name, $root.click: toggleSelected></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
}
在viewmodel中,将所有凭据放在一个可观察数组中(凭证的每个属性也应该是可观察的),然后viewmodel必须做的唯一工作(只要Selected属性是可观察的)
toggleSelection = function(credential) {
credential.Selected = !credential.Selected;
}
然后,当您需要使用所选凭据时,只需过滤数组以查找所选凭据。
祝你好运。编辑:关于Credential类,假设唯一的属性是Name和Selected,可能看起来像:
function Credential(name, selected) {
this.Name = ko.observable(name);
this.Selected = ko.observable(selected);
}
然后你可以遍历你的JSON数据数组
var Credentials = ko.observableArray();
credentialsFromJson.forEach(function(c) {
var credential = new Credential(c.Name, c.Selected);
Credentials.push(credential);
}
这使得每个属性都可以观察到。如果您想要观看很多属性,请查看上面提到的ko.mapping插件。
这有帮助吗?如果我正确地读取代码,计算出的数组不会更新,因为KO正在观察没有发生任何事情,并且使Selected属性可观察应该可以解决这个问题。