22

这是我的场景。我正在使用淘汰映射插件为我创建一个可观察的视图模型层次结构。我的层次结构中有嵌套元素。在层次结构中的特定点,我想放置一个添加按钮以在 observablearray 中插入该元素的新空白副本。问题是我不能只说whateverArray.push(new MyObject())。

由于映射插件实际上为我创建了整个层次结构,因此我无权访问“MyObject”。因此,插入新项目似乎我唯一能做的就是查看前一个项目并复制它。我尝试了 ko.utils.extend 函数,但这似乎并没有进行实际的克隆。它给了我一个对象,但是当我更新该对象时,它仍然会影响从中复制它的原始对象。

请参阅 jsfiddle示例

4

2 回答 2

39

可能有一种方法可以在映射设置中进行设置,但我还不能完全弄清楚。

同时,您可以取消映射对象并将其映射回来,因此您实际上是在制作副本。

var newJob = ko.mapping.fromJS(ko.mapping.toJS(job));

这将是最简单的方法,就像任何其他库一样,再次“反序列化”和“序列化”。


我一直在寻找一种使用映射选项的好方法,并找到了一种方法。

默认情况下,映射插件将从源对象中获取可观察实例,并在目标对象中使用相同的实例。所以实际上,两个实例将共享相同的 observables(错误?)。我们需要做的是为每个属性创建一个新的 observable 并将值复制过来。

幸运的是,有一个方便的实用函数来映射对象的每个属性。然后我们可以创建新的可观察实例,并使用这些值的副本进行初始化。

// Deep copy
var options = {
    create: function (options) {
        // map each of the properties
        return ko.mapping.visitModel(options.data, function (value) {
            // create new instances of observables initialized to the same value
            if (ko.isObservable(value)) { // may want to handle more cases
                return ko.observable(value);
            }
            return value;
        });
    }
};
var newJob = ko.mapping.fromJS(job, options);

请注意,这将是一个浅拷贝,如果您想要一个深拷贝,您可能必须递归地映射对象。但是,这将解决您示例中的问题。

于 2012-09-09T00:12:48.670 回答
7
ko.utils.clone = function (obj) {
    var target = new obj.constructor();
    for (var prop in obj) {
        var propVal = obj[prop];
        if (ko.isObservable(propVal)) {
            var val = propVal();
            if ($.type(val) == 'object') {
                target[prop] = ko.utils.clone(val);
                continue;
            }
            target[prop](val);
        }
    }
    return target;
};

这是我的解决方案,希望对您有所帮助。在此代码中,obj将是您的 viewModel 对象。

于 2014-10-28T03:33:17.457 回答