【问题标题】:Knockout mapping plugin: make every node in hierarchical object structure observableKnockout 映射插件:使分层对象结构中的每个节点都可观察
【发布时间】:2014-09-19 14:51:46
【问题描述】:

我正在使用 Knockout 和 ko.mapping 插件来创建和更新我的视图模型。我有一个来自服务器的这样的 json 结构,例如:

var viewmodel = {
    name: "Foo",
    person: {
        forename: "John",
        surname: "Smith"
    }
};

当我使用ko.mapping.fromJS(viewmodel) 创建我的视图模型时,只有叶节点被转换为可观察对象,所以我得到类似于以下内容:

var viewmodel = {
    name: ko.observable("Foo"),
    person: {
        forename: ko.observable("John"),
        surname: ko.observable("Smith")
    }
};

但我需要每个属性都是可观察的(在此示例中,person 也必须是可观察的),因为我有一些自定义绑定可以处理复杂的可观察对象。 如何配置映射插件以将 每个 属性转换为 observable?

我知道我可以使用这样的东西:

var mapping = {
    'person': {
        create: function (options) {
            var myPersonData = ko.mapping.fromJS(options.data);
            return ko.observable(myPersonData);
        }
    }
};

ko.mapping.fromJS(viewmodel, mapping);

但我需要一个动态解决方案,因为我不知道属性名称(例如“人”)。服务器生成一个动态 json 对象并将其返回给客户端(带有绑定的 HTML 代码也使用正确的属性名称动态创建)。 上面显示的函数必须为 json 对象中的 every 属性执行 - 这可能吗?或者有其他解决方案吗?

【问题讨论】:

    标签: knockout.js mapping observable hierarchical


    【解决方案1】:

    我并不完全相信这是多么合法,但作为一个粗略的解决方案,它似乎确实可以满足您的需求。

    基本上,循环遍历 javascript 数据对象上的所有属性,检查它们是否是您的属性(使用 hasOwnProperty())。然后需要查看属性是什么类型,如果是对象,则需要递归调用makeObservable方法,否则将属性创建为observable。

    我没有实现所有的类型,只有字符串、数组和对象,所以你需要填写其余的:

    function makeObservable(data, viewmodel) {
        var vm = viewmodel || ko.observable({});
        for (var prop in data) {
            if (data.hasOwnProperty(prop)) {
                var ctorType = data[prop].constructor;
                var mappedProperty;
                if (ctorType === String) {
                    mappedProperty = ko.observable(data[prop]);
                } else if (ctorType === Array) {
                    mappedProperty = ko.observableArray();
                    for (var arr in data[prop]) {
                        if (data[prop].hasOwnProperty(arr)) {
                            mappedProperty.push(makeObservable(data[prop][arr]));
                        }
                    }
                } else if (ctorType === Object) {
                    mappedProperty = makeObservable(data[prop]);
                }
    
                if (ko.isObservable(vm)) {
                    vm()[prop] = mappedProperty;
                } else {
                    vm[prop] = mappedProperty;
                }
            }
        }
        return vm;
    }
    
    var viewModel = makeObservable(data, {});
    

    我还创建了一个jsFiddle

    【讨论】:

    • 非常感谢您的快速回答!是的,它会起作用——但是我还必须实现更新功能,并且我必须处理所有不同的类型和特殊情况。我希望使用映射插件并对其进行配置,而不是自己实现所有功能(我不确定这个实现是否真的涵盖了每个用例,因为映射插件有大约 800 行测试代码,用于几乎相同的功能) .
    猜你喜欢
    • 2012-12-03
    • 1970-01-01
    • 2012-03-23
    • 2018-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    相关资源
    最近更新 更多