如何在嵌套模型中自定义挖空映射创建?

时间:2014-02-18 18:15:56

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

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/

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

2 个答案:

答案 0 :(得分:2)

你快到了。直接工作: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语句,因此您可以在控制台中运行代码时看到值,这将有助于了解它是如何工作的。

希望它有所帮助。

答案 1 :(得分:1)

ko.mapping的好处在于流程的自动化程度。 在http://jsfiddle.net/9ejJq/26/

中查看结果

您将注意到我们如何仅使用一个声明的映射来解决问题。

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

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