关于基因敲除.js

Access viewmodel in knockout mapping plugin

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

在映射过程中创建可观察对象时如何访问viewmodel属性?

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

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

编辑:

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);


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

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

第一次映射后,您可以将每个价格作为可观察的价格。在第二次映射之后,您将拥有Total和可观察值。

演示我jsfiddle


一种可能的解决方案是使用{deferEvaluation: true}选项。因此,仅当viewModel准备好并且实际使用了Total属性时,才会对您的计算函数进行求值:

1
2
3
4
5
6
7
8
9
10
11
12
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,那么您还必须更新映射配置。

因为在这种情况下可能无法在映射配置中移动"父"链,所以映射插件不是最佳解决方案...

这是使用手写视图模型并在需要的地方传递"根"的另一种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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。