KnockoutJS映射插件(observableArray)



我是淘汰赛的新手,我在使用映射插件时遇到了问题,因为我不知道它是如何映射我的JSON数据的
这是一个示例json数据,类似于我的程序中的数据:

contact: {
name : 'John',
email : 'address@domain.com',
phones : [{
phoneType : 'Home Phone',
phoneNumber: '999-888-777'},
{
phoneType : 'Business Phone',
phoneNumber: '444-888-777'},
}]
}

正如您所看到的,这个json数据包含一个电话数组
我使用了敲除映射插件,我可以轻松地绑定"姓名"、"电子邮件"并将电话号码循环到"foreach:phones"中,直到我尝试在阵列电话中的对象phoneNumber上进行ko.compute

@section scripts
{
<script src="~/ViewModels/ContactModel.js"></script>
<script type="text/javascript">
var viewModel = new ContactModel(@Html.Raw(Model.ToJson()));
$(document).ready(function () {
ko.applyBindings(viewModel);
});
</script>
<label>Name</label><input data-bind="value: name" />
<label>Email</label><input data-bind="value: email" />
<label>Phones</label>
<table>
<tbody data-bind="foreach: phones">
<tr>
<td><strong data-bind='text: phoneType'></strong></td>
<td><input data-bind='value: phoneNumber' /></td>
</tr>
/tbody>
</table>

这是ContactModel.js

var ContactModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.reformatPhoneNumber = ko.computed(function(){
var newnumber;
newnumber = '+(1)' + self.phones().phoneNumber;
return newnumber;
});
};

对于视觉表示,这就是现在的样子:

Name: John
Email: address@domain.com
Phones:
<--foreach: phones -->
Home Phone: 999-888-777
Business Phone: 444-888-777

我想做的是重新格式化phoneNumber以这种方式显示:

Name: John
Email: address@domain.com
Phones:
<--foreach: phones -->
Home Phone: (+1)999-888-777
Business Phone: (+1)444-888-777

我试着在绑定中使用重新格式化的phoneNumber来代替phoneNumber,如下所示:

<table>
<tbody data-bind="foreach: phones">
<tr>
<td><strong data-bind='text: phoneType'></strong></td>
<td><input data-bind='value: $root.reformatPhoneNumber' /></td>
</tr>
/tbody>
</table>

但当我这样做时,重新格式化PhoneNumber的值不会出现。我在这里读到,我必须使observableArray中的对象也可观测,因为默认情况下ko.mapping不会这样做。但我无法想象如何做到这一点,因为我是这个jslibrary的新手,所以我希望ko.mapping插件能自动为我完成所有的工作
如有任何帮助,我们将不胜感激。非常感谢!!

使用命名(一个名为reformatPhoneNumber的计算)表明您将计算视为函数。虽然它们在技术上是函数,但它们表示值。将它们视为值,就像对待可观察性一样。在您的情况下,这意味着它应该更像formattedPhoneNumber,并且应该作为电话号码的属性而不是联系人的属性存在。

将您的模型划分为单独的单元,这些单元可以从原始数据中引导自己。

模型层次结构中最小的信息单元是一个电话号码:

function PhoneNumber(data) {
var self = this;
self.phoneType = ko.observable();
self.phoneNumber = ko.observable();
self.formattedPhoneNumber = ko.pureComputed(function () {
return '+(1) ' + ko.unwrap(self.phoneNumber);
});
ko.mapping.fromJS(data, PhoneNumber.mapping, self);
}
PhoneNumber.mapping = {};

层次结构中的下一个是联系人。它包含电话号码。

function Contact(data) {
var self = this;
self.name = ko.observable();
self.email = ko.observable();
self.phones = ko.observableArray();
ko.mapping.fromJS(data, Contact.mapping, self);
}
Contact.mapping = {
phones: {
create: function (options) {
return new PhoneNumber(options.data);
}
}
};

接下来是联系人列表(或电话簿),其中包含联系人:

function PhoneBook(data) {
var self = this;
self.contacts = ko.observableArray();
ko.mapping.fromJS(data, PhoneBook.mapping, self);
}
PhoneBook.mapping = {
contacts: {
create: function (options) {
return new Contact(options.data);
}
}
};

现在,您可以通过实例化PhoneBook对象来创建整个对象图:

var phoneBookData = {
contacts: [{
name: 'John',
email: 'address@domain.com',
phones: [{
phoneType: 'Home Phone',
phoneNumber: '999-888-777'
}, {
phoneType: 'Business Phone',
phoneNumber: '444-888-777'
}]
}]
};
var phoneBook = new PhoneBook(phoneBookData);

阅读映射插件的文档。

展开以下代码片段以查看其工作情况。

function PhoneBook(data) {
var self = this;
self.contacts = ko.observableArray();

ko.mapping.fromJS(data, PhoneBook.mapping, self);
}
PhoneBook.mapping = {
contacts: {
create: function (options) {
return new Contact(options.data);
}
}
};
// ------------------------------------------------------------------
function Contact(data) {
var self = this;

self.name = ko.observable();
self.email = ko.observable();
self.phones = ko.observableArray();

ko.mapping.fromJS(data, Contact.mapping, self);
}
Contact.mapping = {
phones: {
create: function (options) {
return new PhoneNumber(options.data);
}
}
};
// ------------------------------------------------------------------
function PhoneNumber(data) {
var self = this;

self.phoneType = ko.observable();
self.phoneNumber = ko.observable();
self.formattedPhoneNumber = ko.pureComputed(function () {
return '+(1) ' + ko.unwrap(self.phoneNumber);
});

ko.mapping.fromJS(data, PhoneNumber.mapping, self);
}
PhoneNumber.mapping = {};
// ------------------------------------------------------------------
var phoneBook = new PhoneBook({
contacts: [{
name: 'John',
email: 'address@domain.com',
phones: [{
phoneType: 'Home Phone',
phoneNumber: '999-888-777'
}, {
phoneType: 'Business Phone',
phoneNumber: '444-888-777'
}]
}]
});
ko.applyBindings(phoneBook);
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<ul data-bind="foreach: contacts">
<li>
<div data-bind="text: name"></div>
<div data-bind="text: email"></div>
<ul data-bind="foreach: phones">
<li>
<span data-bind="text: phoneType"></span>:
<span data-bind="text: formattedPhoneNumber"></span>
</li>
</ul>
</li>
</ul>
<hr />
Model data:
<pre data-bind="text: ko.toJSON(ko.mapping.toJS($root), null, 2)"></pre>
Viewmodel data:
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

最新更新