我使用Knockout.js作为MVVM库到我的数据绑定到一些网页。 我目前正在建设一个图书馆,使REST调用Web服务。 我的RESTful Web服务返回一个简单的结构:
{
id : 1,
details: {
name: "Johnny",
surname: "Boy"
}
}
我有一个观察的主父, myObject
。 当我做
myObject(ko.mapping.fromJS(data))
在观测myObject
是:
我怎样才能使details
(理论上在结构上可观察到的任何对象)? 我需要这种行为,这样我可以设置一个计算观察到的细节,并得到尽快的任何内部数据的变化发现。
我已经建立了一个基本的递归函数,它应该做的伎俩。 它不,当然, myObject.details
不会成为可观察到的。
// Makes every object in the tree an observable.
var makeAllObservables = function () {
makeChildrenObservables(myObject);
};
var makeChildrenObservables = function (object) {
// Make the parent an observable if it's not already
if (!ko.isObservable(object)) {
if ($.isArray(object))
object = ko.observableArray(object);
else
object = ko.observable(object);
}
// Loop through its children
for (var child in object()) {
makeChildrenObservables(object()[child]);
}
};
我敢肯定这件事情有关不正确的引用,但我该如何解决这个问题? 谢谢。
Answer 1:
我不认为淘汰赛有一个内置的方式来观察变化的子元素。 如果我理解你的问题,当有人更名想要更改的细节作为一个实体被察觉。 你能给的你将如何使用这一个具体的例子? 你会使用订阅可观察到执行某些操作细节?
您的代码不作细节的观察到的原因是因为JavaScript是按值传递,那么改变你的函数的“对象”参数的值不会改变你传递的实际价值,只是里面的参数值的功能。
编辑
如果更改会自动传播给家长,这应该让所有的孩子观察到的我想,但你的根,你第一时间传递应该已经是可观察的。
// object should already be observable
var makeChildrenObservables = function (object) {
if(!ko.isObservable(object)) return;
// Loop through its children
for (var child in object()) {
if (!ko.isObservable(object()[child])) {
object()[child] = ko.observable(object()[child]);
}
makeChildrenObservables(object()[child]);
}
};
Answer 2:
我会用淘汰赛映射插件 。
var jsonData = {
id : 1,
details: {
name: "Johnny",
surname: "Boy"
}
}
var yourMapping = {
'details': {
create: function(options) {
return Details(options.data);
}
}
}
function Details(data) {
ko.mapping.fromJS(data, {}, this);
}
function YourObjectName() {
ko.mapping.fromJS(jsonData, yourMapping, this);
}
这将与所有的孩子可观的创建对象层次。
Answer 3:
从我都经历过,ko.mapping.fromJS不会使可观察出的一个对象。
比方说,你有这样的视图模型构造函数:
var VM = function(payload) {
ko.mapping.fromJS(payload, {}, this);
}
并且该数据对象:
var data1 = {
name: 'Bob',
class: {
name: 'CompSci 101',
room: 112
}
}
并使用数据1创建VM1:
var VM1 = new VM(data1);
然后VM1.class不会是ko.observable,这是一个普通的JavaScript对象。
如果您然后使用一个数据对象有一个空的类成员,即创建另一个视图模型:
var data2 = {
name: 'Bob',
class: null
}
var VM2 = new VM(data2);
然后VM2.class是ko.observable。
如果你再执行:
ko.mapping(data1, {}, VM2)
然后VM2.class仍然ko.observable。
所以,如果你从那里对象成员是空的种子数据对象创建一个视图模型,然后用填充的数据对象这样就把它们,你将有可观察到的类成员。
这导致的问题,因为有时对象成员都是可观的,有时他们没有。 表单绑定将与VM1工作,而不是与VM2工作。 这将是很好,如果ko.mapping.fromJS总是让一切ko.observable所以它是一致的?
Answer 4:
通过采用淘汰赛插件 ,我们可以让孩子观察到的元素。我们有很多选项来管理如何,我们希望我们的数据进行观察的。
下面是一个示例代码:
var data = {
people: [
{
id: 1,
age: 25,
child : [
{id : 1,childname : "Alice"},
{id : 2,childname : "Wonderland"}
]
},
{id: 2, age: 35}
],
Address:[
{
AddressID : 1,
City : "NewYork",
cities : [
{
cityId : 1,
cityName : "NewYork"
},
{
cityId :2,
cityName : "California"
}
]
},
{
AddressID : 2,
City : "California",
cities : [
{
cityId :1,
cityName : "NewYork"
},
{
cityId :2,
cityName : "California"
}
]
}
],
isSelected : true,
dataID : 6
};
var mappingOptions = {
people: {
create: function(options) {
console.log(options);
return ko.mapping.fromJS(options.data, childmappingOptions);
}
},
Address: {
create: function(options) {
console.log(options);
return ko.mapping.fromJS(options.data, childmappingOptions);
}
}
};
var childmappingOptions = {
child: {
create: function(options) {
return ko.mapping.fromJS(options.data, { observe: ["id","childname"]});
}
},
cities :{
create: function(options) {
return ko.mapping.fromJS(options.data, { observe: ["cityId","cityName"]});
}
}
};
var r = ko.mapping.fromJS(data, mappingOptions);
我附上一个工作小提琴: http://jsfiddle.net/wmqTx/5/
Answer 5:
我将延长保德尔世界报 “的回答(我想可能很容易被最好的,此时唯一的解决方案),与我的示例解决方案。
考虑frapontillo的原始对象:
{
id : 1,
details: {
name: "Johnny",
surname: "Boy"
}
}
在details
属性本身是一个对象,因此无法可观察到的。 这同样适用于所述User
在下面的示例性,这也是一个目的。 这两个对象不能观测但他们的LEAF属性即可 。
您的数据树/模型的每一片叶子属性可以是可观察的。 实现最简单的方法是,你正确将它传递给映射插件作为参数之前定义的映射模型 。
请参阅下面我的例子。
例:
比方说,我们需要显示一个HTML页面/视图,我们有在网格上的用户列表。 旁边的用户网格示出了用于编辑从电网所选择的用户的形式。
第1步:定义模型
function UsersEdit() {
this.User = new User(); // model for the selected user
this.ShowUsersGrid = ko.observable(false); // defines the grid's visibility (false by default)
this.ShowEditForm = ko.observable(false); // defines the selected user form's visibility (false by default)
this.AllGroups = []; // NOT AN OBSERVABLE - when editing a user in the user's form beside the grid a multiselect of all available GROUPS is shown (to place the user in one or multiple groups)
this.AllRoles = []; // NOT AN OBSERVABLE - when editing a user in the user's form beside the grid a multiselect of all available ROLES is shown (to assign the user one or multiple roles)
}
function User() {
this.Id = ko.observable();
this.Name = ko.observable();
this.Surname = ko.observable();
this.Username = ko.observable();
this.GroupIds = ko.observableArray(); // the ids of the GROUPS that this user belongs to
this.RoleIds = ko.observableArray(); // the ids of the ROLES that this user has
}
步骤2:映射(TO GET NESTED观测)
比方说,这是你生的JSON模式与要映射,并得到嵌套观测KO了模型数据。
var model = {
User: {
Id: 1,
Name: "Johnny",
Surname = "Boy",
Username = "JohhnyBoy",
GroupIds = [1, 3, 4],
RoleIds = [1, 2, 5]
}
};
现在,这一切被定义,你可以映射:
var observableUserEditModel = ko.mapping.fromJS(model, new UsersEdit());
就大功告成了! :)
该observableUserEditModel将保留所有的观测,甚至嵌套的人的。 现在,你需要为了测试这种照顾的唯一一件事就是绑定observableUserEditModel
对象与你的HTML。 提示:使用with
约束力和测试观察到的observableUserEditModel
数据结构中的HTML视图中插入这样的:
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
Answer 6:
也许在未来的版本中有可能是导致ko.mapping.fromJS总是创造可观的配置选项。 它可以为新项目或更新现有项目的绑定后启用。
我要做的,以防止这个问题,是确保模型的种子总是有对象的成员属性填充,一级抓一级。 这样一来,所有的对象属性被映射为的POJO(普通老式JavaScript对象),所以视图模型不将它们作为初始化ko.observables。 它避免了“有时观测,有时没有”的问题。
最好的问候,麦克
文章来源: Knockout.js Make every nested object an Observable