KnockoutJS 映射插件 (observableArray)
KnockoutJS Mapping Plugin (observableArray)
我是 knockout 的新手,我在使用映射插件时遇到问题,因为我不明白它是如何映射我的 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 数据包含一个 phone 数组。
我使用了敲除映射插件,我可以绑定 'name'、'email' 并在 'foreach: phones' 中循环 phone 数字,直到我尝试制作 ko.compute 在 phoneNumber 上,它是数组 phones 中的一个对象。
@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
我想做的是重新格式化 phone 数字以这样显示它:
Name: John
Email: address@domain.com
Phones:
<--foreach: phones -->
Home Phone: (+1)999-888-777
Business Phone: (+1)444-888-777
我尝试通过在我的绑定中使用 reformatPhoneNumber 代替 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>
但是当我这样做时,没有出现 reformatPhoneNumber 的值。
我在这里的某处读到,我必须使我的 observableArray 中的对象也可观察到,因为 ko.mapping 默认情况下不这样做。但是我无法想象如何去做,因为我是这个 jslibrary 的新手,我希望 ko.mapping 插件自动为我完成所有工作。
任何帮助将不胜感激。非常感谢!!
您对命名的使用(一个名为 reformatPhoneNumber
的计算)表明您将计算视为函数。虽然从技术上讲,它们是函数,但它们 代表 值。将它们视为值,就像对待可观察对象一样。在你的情况下,这意味着它应该更像 formattedPhoneNumber
并且应该作为 phone 号码的 属性 存在,而不是作为联系人的 属性。
将您的模型分成单独的单元,这些单元可以 bootstrap 自身来自原始数据。
模型层次结构中的最小信息单位是 phone 数字:
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 = {};
层次结构中的下一个是联系人。它包含 phone 个数字。
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);
}
}
};
接下来是联系人列表(或phone书),其中包含联系人:
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);
}
}
};
现在您可以通过实例化电话簿对象来创建整个对象图:
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);
通读documentation of the mapping plugin。
展开以下代码片段以查看其工作情况。
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>
我是 knockout 的新手,我在使用映射插件时遇到问题,因为我不明白它是如何映射我的 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 数据包含一个 phone 数组。
我使用了敲除映射插件,我可以绑定 'name'、'email' 并在 'foreach: phones' 中循环 phone 数字,直到我尝试制作 ko.compute 在 phoneNumber 上,它是数组 phones 中的一个对象。
@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
我想做的是重新格式化 phone 数字以这样显示它:
Name: John
Email: address@domain.com
Phones:
<--foreach: phones -->
Home Phone: (+1)999-888-777
Business Phone: (+1)444-888-777
我尝试通过在我的绑定中使用 reformatPhoneNumber 代替 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>
但是当我这样做时,没有出现 reformatPhoneNumber 的值。
我在这里的某处读到,我必须使我的 observableArray 中的对象也可观察到,因为 ko.mapping 默认情况下不这样做。但是我无法想象如何去做,因为我是这个 jslibrary 的新手,我希望 ko.mapping 插件自动为我完成所有工作。
任何帮助将不胜感激。非常感谢!!
您对命名的使用(一个名为 reformatPhoneNumber
的计算)表明您将计算视为函数。虽然从技术上讲,它们是函数,但它们 代表 值。将它们视为值,就像对待可观察对象一样。在你的情况下,这意味着它应该更像 formattedPhoneNumber
并且应该作为 phone 号码的 属性 存在,而不是作为联系人的 属性。
将您的模型分成单独的单元,这些单元可以 bootstrap 自身来自原始数据。
模型层次结构中的最小信息单位是 phone 数字:
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 = {};
层次结构中的下一个是联系人。它包含 phone 个数字。
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);
}
}
};
接下来是联系人列表(或phone书),其中包含联系人:
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);
}
}
};
现在您可以通过实例化电话簿对象来创建整个对象图:
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);
通读documentation of the mapping plugin。
展开以下代码片段以查看其工作情况。
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>