【问题标题】:Access viewmodel in knockout mapping plugin在敲除映射插件中访问视图模型
【发布时间】:2014-06-06 13:49:15
【问题描述】:

我正在使用敲除映射插件将计算属性添加到可观察数组中的项目。但是,此计算属性依赖于我的视图模型中的不同属性。

在映射期间创建可观察对象时如何访问视图模型属性?

请注意,我不能使用 options.parent,因为该属性在 viewModel 中更靠前。

我也无法更改视图模型,因为它是在服务器端生成的。

编辑:

这是一个显示问题的 JSFiddle。被注释掉的行是我需要开始工作的。

http://jsfiddle.net/g46mt/2/

这是我现在所拥有的,但显然是在抛出错误:

var mapping = {
    'Collection': {
        create: function(options) {
            var model = ko.mapping.fromJS(options.data);
            model.Total = ko.computed(function() {
                var result = this.Price() * viewModel.Count(); // :(
                return result;
            }, model);

            return model;
        }
    }
};

var json = { ... large json object ... };
var viewModel = ko.mapping.fromJS(json, mapping);

【问题讨论】:

  • 请至少发布您的 json 结构的相关部分!我们至少需要CollectionPriceCount 属性的位置,以及您希望在哪里拥有Total 属性。
  • 我不认为 json 是相关的,因为问题不在于特定的 json 结构。但我添加了一个显示问题的有效 JSFiddle。

标签: knockout.js knockout-mapping-plugin


【解决方案1】:

一种可能的解决方案是使用{deferEvaluation: true} 选项。因此,只有在 viewModel 准备好并且实际使用了 Total 属性时,才会评估您的计算函数:

var mapping = {
    'Collection': {
        create: function(options) {
            var model = ko.mapping.fromJS(options.data);
            model.Total = ko.computed(function() {
                var result = this.Price() * viewModel.Count();
                return result;
            }, model, {deferEvaluation: true});
            return model;
        }
    }
};

演示JSFiddle.

但是,通过这种方法,您可以将视图模型名称与映射选项紧密结合。因为如果您更改了 var viewModel = ko.mapping.fromJS(json, mapping); 并将您的 viewModel 命名为不同的名称,那么您还必须更新映射配置。

因为没有办法在映射配置中遍历“父”链,可能对于这种情况,映射插件不是最好的解决方案......

这是一种替代方法,使用手写视图模型并在需要的地方传递“根”:

var MainViewModel = function (json) {    
    ko.mapping.fromJS(json, { 'ignore': ["Foo"] }, this); //map the rest
    this.Foo = new FooViewModel(json.Foo, this);
}

var FooViewModel = function (json, root) {
    ko.mapping.fromJS(json, { 'ignore': ["Bar"] }, this); //map the rest
    this.Bar = new BarViewModel(json.Bar, root);
}

var BarViewModel = function (json, root) {
    ko.mapping.fromJS(json, { 'ignore': ["Collection"] }, this); //map the rest
    this.Collection = ko.mapping.fromJS(json.Collection, {
       create: function(options) {
            var model = ko.mapping.fromJS(options.data);
            model.Total = ko.computed(function() {
                var result = this.Price() * root.Count();
                return result;
            }, model);

            return model;

       }});
}

演示JSFiddle.

【讨论】:

    【解决方案2】:

    使用映射插件,可以从多个来源进行映射。我认为你可以这样做

    var viewModel = ko.mapping.fromJS(json);
    viewModel = ko.mapping.fromJS(json, mapping, viewModel),
    

    在第一次映射后,您的 Collection 中的每个 Price 都是可观察的。在第二次映射之后,您将拥有 Total 和 observable。

    demo i jsfiddle

    【讨论】:

    • 是的,但是这个解决方案遍历了整个json结构两次,它也没有解决映射配置中有viewModel变量名的问题...
    • @nemesv 我知道它会遍历结构两次,我确实喜欢您提出的第二个解决方案,它可以防止这种情况发生。 viewModel 变量名在我看来不是一个需要担心的问题。如果 json 结构中的 Count 变量改名了怎么办?这对我来说是映射配置中的同等依赖。
    • Count 和实际上的Price 是不同的依赖关系。仅当 JSON 结构发生更改时才需要更改它们,并且无法避免这种情况。如果合同/接口发生变化,则两端都需要更改...但是viewModel 是对变量名称的不同依赖项,可以独立更改,甚至无需意识到存在依赖项。通过简单的重构(重命名局部变量),您可以在完全不相关的地方破坏您的代码,这是非常危险的。
    猜你喜欢
    • 2014-08-01
    • 1970-01-01
    • 2012-06-16
    • 2012-04-13
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 2014-01-21
    相关资源
    最近更新 更多