【问题标题】:How do I customize knockout mapping creation in nested model?如何在嵌套模型中自定义剔除映射创建?
【发布时间】:2014-03-18 16:46:34
【问题描述】:

对 Knockout 来说是全新的,我正在尝试使用 Knockout 映射插件将来自服务器的 JSON 响应映射到特定模型。模型是嵌套的,我正在尝试使用 create 回调覆盖对象构造,即使在嵌套模型中也是如此。但是,我的映射选项似乎没有被正确读取。示例 JSON:

{
    "EmployeeFeedbackRequestSubmissions": [
        {
            "EmployeeFeedbackRequestSubmissionId": 0,
            "Employee": "John Smith0",
            "EmployeesWorkedWith": [
                {
                    "EmployeeName": "Joe Smith",
                    "ProjectsWorked": [
                        {
                            "ProjectName": "Document Management Console"
                        },
                        {
                            "ProjectName": "Performance Eval Automation"
                        },
                        {
                            "ProjectName": "Business Tax Extensions"
                        }
                    ]
                },
                {
                    "EmployeeName": "Michael Jones",
                    "ProjectsWorked": [
                        {
                            "ProjectName": "Document Management Console"
                        },
                        {
                            "ProjectName": "Performance Eval Automation"
                        },
                        {
                            "ProjectName": "Business Tax Extensions"
                        }
                    ]
                },
                {
                    "EmployeeName": "Jason Smith",
                    "ProjectsWorked": [
                        {
                            "ProjectName": "Document Management Console"
                        },
                        {
                            "ProjectName": "Performance Eval Automation"
                        },
                        {
                            "ProjectName": "Business Tax Extensions"
                        }
                    ]
                },
                {
                    "EmployeeName": "Robert Will",
                    "ProjectsWorked": [
                        {
                            "ProjectName": "Document Management Console"
                        },
                        {
                            "ProjectName": "Performance Eval Automation"
                        },
                        {
                            "ProjectName": "Business Tax Extensions"
                        }
                    ]
                }
            ]
        }
        // more EmployeeFeedbackRequestSubmissions
    ]
}

映射选项:

var mappingOptions = {
    // overriding default creation/initialization code
    'EmployeeFeedbackRequestSubmissions': {
        create: function (options) {
            return (new(function () {
                this.EmployeeHeading = ko.computed(function () {
                    return "Performance Evaluation Employee: " + this.Employee();
                }, this);

                ko.mapping.fromJS(options.data, {}, this);
            })());
        },
            'EmployeesWorkedWith': {
            create: function (options) {
                return new instance.EmployeesWorkedWithModel(options.data);
            }
        }
    }
};

完整示例的示例小提琴:http://jsfiddle.net/jeades/9ejJq/2/

结果应该是能够使用从EmployeesWorkedWithModel 计算得到的nameUpper。我也愿意接受有关更好方法的建议,因为这可能不是处理此问题的最佳方法。

【问题讨论】:

    标签: json knockout.js knockout-mapping-plugin


    【解决方案1】:

    你快到了。直接开始工作:http://jsfiddle.net/jiggle/na93A/

    映射选项对象不需要嵌套,映射插件会从名称中查找映射,当你将它们传递给 ko.mapping.fromJSON 时

    所以你的映射选项对象应该是单层的:

        var self = this;
    
        self.mappingOptions = {
            // overriding default creation/initialization code
            'EmployeeFeedbackRequestSubmissions': {
                create: function (options) {
                    return (new(function () {
                        this.EmployeeHeading = ko.computed(function () {
                            return "Performance Evaluation Employee: " + this.Employee();
                        }, this);
    
                        ko.mapping.fromJS(options.data, self.mappingOptions, this);
                    })());
                }
            },
            'EmployeesWorkedWith': {
                    create: function (options) {
                       // return new instance.EmployeesWorkedWithModel(options);
                        return (new(function(){
                            ko.mapping.fromJS(options.data, {}, this);
    
                            this.nameUpper = ko.computed(function () {
                                return this.EmployeeName().toUpperCase();
                            }, this);
                        })());
                    }
            }
    
        };
    

    请注意,我使用“self”作为对“this”而不是“instance”的本地引用,只是为了使代码更易于阅读(就像您在主视图模型中使用的“instance”一样)。

    我还将 mappingOptions 对象作为 FeedbackViewModel 的一部分,因为我们需要将其传递到 mapping.fromJS 调用中,因此当它在数据中看到“EmployeesWorkedWith”级别时,它将拥有它的 mappingOptions。

    发件人:

    ko.mapping.fromJS(options.data, {}, this);
    

    收件人:

    ko.mapping.fromJS(options.data, self.mappingOptions, this);
    

    然后,您可以将“EmployeesWorkedWith”级别的创建代码移动到 create 中(您可以调用一个函数,但我已将它一起保存在 mappingOptions 中,如上所示,就像您创建“EmployeeFeedbackRequestSubmissions”级别的方式一样.

    然后您可以完全摆脱 instance.EmployeesWorkedWithModel 函数。

    可以在这里找到一个工作小提琴:

    http://jsfiddle.net/jiggle/na93A/

    或者,您可以在为“EmployeeFeedbackRequestSubmissions”创建时创建单独的 mappingOptions 对象,并且在一个对象中没有所有级别的映射,这可以在这个小提琴http://jsfiddle.net/jiggle/Avam7/中看到

    取决于您喜欢哪种编码风格,如果您对不同级别有不同的映射需求并且它们具有相同的集合名称,则将它们分开很重要。

    例如。

    员工

    员工

    员工(在这个级别您可能需要不同的计算等)

    如果是这样,您将使用第二个选项(分离 mappingOptions 并传递给将使用它的级别)

    我在 fiddles 中添加了一些 console.log 语句,这样您就可以在代码在控制台中运行时看到值,这将有助于了解它是如何工作的。

    希望对你有帮助。

    【讨论】:

    • 感谢您提供的多个示例和解释!
    • Jason,不客气,感谢您的评论,当您有机会尝试答案时,您会注意到使用 beauXjames 答案时,您会丢失计算结果。 nameUpper 等,因为他的示例实际上并没有为您的数据的 EmployeesWorkedWith 级别运行任何映射,它只是创建数据。干杯约翰。
    • 是的,感谢您指出这一点。我的主要问题是尝试将其他计算属性和函数附加到嵌套模型。否则,我不需要重写任何对象构造。再次感谢。
    【解决方案2】:

    ko.mapping 的好处在于该过程的自动化程度。 查看http://jsfiddle.net/9ejJq/26/中的结果

    您会注意到我们如何只使用一个声明的映射来启动。

    feedbackMappingOptions = {
        create: function (options) {
            return new FeedbackViewModel(options.data);
        }
    };
    

    从那时起,每个视图模型都会触发其子对象的映射。您可以为每个创建一个映射选项,或者正如您在EmployeesWorkedWith 下的最终ProjectsWorked 对象中看到的那样,我们只需将数据直接放入映射,然后ko.mapping 会完成其余的工作。希望这会有所帮助。

    【讨论】:

    • 哦,记住...一旦您在映射中提供了自定义创建方法,您确实需要在您正在创建的视图模型中声明您的属性...它们不会被自动声明.
    • 太棒了。感谢您的帮助和时间!
    • beauXjames,但他失去了他的名字Upper 计算,这就是他首先进行映射的原因?
    • 计算出来了...只需添加 .toUpperCase() 就可以回到您想要的...更多控制
    猜你喜欢
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多