为什么 knockout.mapping 在某些数据结构上失败?
Why knockout.mapping fails on some data-structures?
使用 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
我的模型中有两个属性(a
和 b
),但我只需要 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
复制某些结构有效而其他结构无效似乎令人费解。我知道,当树中某处存在多级哈希时,问题就会出现。
这是期望的行为还是我这里有什么问题?为什么复制某些结构有效而其他结构无效?
您是否考虑过定义自定义对象构造?详细信息可以在 ko 文档中的 advanced section in "The mapping plugin" page 中找到。
该文档中包含很多选项,用于 JSON 对象映射的不同情况 to/from。
我已经成功复现了您提到的问题:
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>
如您所见,在我的复制中,我包含了两个库的 non-minified 版本。我在错误中介入了它,它就在这里,在这段代码中:
if(options.observe.length > 0 && ko.utils.arrayIndexOf(options.observe, fullPropertyName) == -1)
{
mappedRootObject[indexer] = value(); // <---- THIS LINE
options.copiedProperties[fullPropertyName] = true;
return;
}
这句话让我觉得很奇怪,因为通常对于 KO,如果您不确定它们是普通值还是可观察值,您需要明确需要 "unwrap" 值。
所以我去了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又是buggy/first版本了。
然后再进行一些挖掘,我发现 issue #137 with exactly this problem. That issue ends with the same conclusion I reached: the fix is not included in the 2.4.1 build. There will not likely soon be new builds: as you can see in the project's readme 这个项目目前没有得到积极维护。
底线:您需要解决这种情况,或者创建您自己的自定义映射构建并解决此问题。
使用 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
我的模型中有两个属性(a
和 b
),但我只需要 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
复制某些结构有效而其他结构无效似乎令人费解。我知道,当树中某处存在多级哈希时,问题就会出现。
这是期望的行为还是我这里有什么问题?为什么复制某些结构有效而其他结构无效?
您是否考虑过定义自定义对象构造?详细信息可以在 ko 文档中的 advanced section in "The mapping plugin" page 中找到。
该文档中包含很多选项,用于 JSON 对象映射的不同情况 to/from。
我已经成功复现了您提到的问题:
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>
如您所见,在我的复制中,我包含了两个库的 non-minified 版本。我在错误中介入了它,它就在这里,在这段代码中:
if(options.observe.length > 0 && ko.utils.arrayIndexOf(options.observe, fullPropertyName) == -1)
{
mappedRootObject[indexer] = value(); // <---- THIS LINE
options.copiedProperties[fullPropertyName] = true;
return;
}
这句话让我觉得很奇怪,因为通常对于 KO,如果您不确定它们是普通值还是可观察值,您需要明确需要 "unwrap" 值。
所以我去了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又是buggy/first版本了。
然后再进行一些挖掘,我发现 issue #137 with exactly this problem. That issue ends with the same conclusion I reached: the fix is not included in the 2.4.1 build. There will not likely soon be new builds: as you can see in the project's readme 这个项目目前没有得到积极维护。
底线:您需要解决这种情况,或者创建您自己的自定义映射构建并解决此问题。