【问题标题】:Why knockout.mapping fails on some data-structures?为什么 knockout.mapping 在某些数据结构上失败?
【发布时间】:2016-05-04 16:13:44
【问题描述】:

使用 knockout.mapping 我尝试从 JSON 映射到 ko-object。在尝试使用带有映射选项的更高级解决方案时,我经常得到Uncaught TypeError: g is not a function。我试图找出问题所在,但我仍然感到困惑。

假设我有一个非常简单的模型:

var data1 = { // works
  a: "a",
  b: [ 
    { b1: "v1" }, 
    { b2: "v2" } 
  ] 
};

现在使用这个模型可以像这样正常工作:

function viewModel ( data ) {
  var self = this;
  var a    = ko.mapping.fromJS( data, { observe: "a"} );

  return a;
}

var vm1 = viewModel( data1 ); // works

我的模型中有两个属性(ab),但我只需要 a 即可观察到,而 b 应该只是复制到视图模型中。

遗憾的是,如果数据结构变得更深,它就不能很好地工作:

var data1 = { // works
  a: "a",
  b: [ 
    { b1: "v1" }, 
    { b2: "v2" } 
  ] 
};

var data2 = { // Uncaught TypeError: g is not a function
  a: "a",
  b: [ 
    { b1: { name: "v1" } }, 
    { b2: { name: "v2" } } 
  ]
};

var data3 = { // Uncaught TypeError: g is not a function
  a: "a",
  b1: { name: "v1" }, 
  b2: { name: "v2" } 
};

var data4 = { // works
  a: "a",
  b1: "v1", 
  b2: "v2"  
};

var data5 = { // works
  a: "a",
  b1: ["1::v1", "2::v1"], 
  b2: ["1::v2", "2::v2"]  
};

function viewModel ( data ) {
  var self = this;
  var a    = ko.mapping.fromJS( data, { observe: "a"} );

  return a;
}

var vm1 = viewModel( data1 ); // works
var vm2 = viewModel( data2 ); // Uncaught TypeError: g is not a function
var vm3 = viewModel( data3 ); // Uncaught TypeError: g is not a function
var vm4 = viewModel( data4 ); // works
var vm5 = viewModel( data5 ); // works

复制某些结构有效而其他无效似乎令人费解。我明白,当树中某处存在多级哈希时,这个问题就会出现。

这是期望的行为还是我这里有什么问题?为什么复制某些结构有效而其他无效?

【问题讨论】:

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


    【解决方案1】:

    我已经成功重现了你提到的问题:

    var data1 = { // works
      a: "a",
      b: [ 
        { b1: "v1" }, 
        { b2: "v2" } 
      ] 
    };
    
    var data2 = { // Uncaught TypeError: g is not a function
      a: "a",
      b: [ 
        { b1: { name: "v1" } }, 
        { b2: { name: "v2" } } 
      ]
    };
    
    function viewModel ( data ) {
      var self = this;
      var a = ko.mapping.fromJS( data, { observe: ["a"]} );
      return a;
    }
    
    var vm1 = viewModel( data1 ); // works
    var vm2 = viewModel( data2 ); // Uncaught TypeError: g is not a function
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-debug.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>

    如您所见,在我的 repro 中,我包含了两个库的非缩小版本。我在错误中介入了它,它就在这里,在这段代码中:

    if(options.observe.length > 0 && ko.utils.arrayIndexOf(options.observe, fullPropertyName) == -1)
    {
        mappedRootObject[indexer] = value(); // <---- THIS LINE
        options.copiedProperties[fullPropertyName] = true;
        return;
    }
    

    这行让我觉得很奇怪,因为通常对于 KO,如果您不确定它们是普通值还是可观察值,您需要明确地需要“解包”值。

    于是我去了the relevant source code on Github,但令我惊讶的是,CDNJS版本的上述代码不存在,这是不同的:

    if(options.observe.length > 0 && ko.utils.arrayIndexOf(options.observe, fullPropertyName) == -1)
    {
        mappedRootObject[indexer] = ko.utils.unwrapObservable(value); // <-- DIFFERENT
        options.copiedProperties[fullPropertyName] = true;
        return;
    }
    

    这条线是我所期望的。

    再一次,the most recent debug build 再次拥有错误/第一个版本。

    然后再进行一些挖掘,我看到issue #137 正是这个问题。该问题以我得出的相同结论结束:该修复不包含在 2.4.1 版本中。不太可能很快会有新版本:正如您在 the project's readme 中看到的那样,该项目目前没有得到积极维护。

    底线:您需要解决这种情况,或者创建自己的自定义映射构建以解决此问题。

    【讨论】:

    • 谢谢!你的回答是彻底和足够的。我现在可能不再用头撞墙了……
    【解决方案2】:

    您是否考虑过定义自定义对象构造?详细信息可以在 ko 文档中的advanced section in "The mapping plugin" page 中找到。

    该文档中包含相当多的选项,用于映射到/从的 JSON 对象的不同情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-20
      • 2019-03-23
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      • 2019-03-12
      • 1970-01-01
      相关资源
      最近更新 更多