Knockout.js让每嵌套对象的可观察(Knockout.js Make every neste

2019-06-24 08:53发布

我使用Knockout.js作为MVVM库到我的数据绑定到一些网页。 我目前正在建设一个图书馆,使REST调用Web服务。 我的RESTful Web服务返回一个简单的结构:

{
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

我有一个观察的主父, myObject 。 当我做

myObject(ko.mapping.fromJS(data))

在观测myObject是:

  • id
  • name
  • surname

我怎样才能使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