我有一个 API 端点,可以输出简单的 JSON,如下所示:
{
"num_results": 2,
"objects": [
{
"creator": null,
"id": 1,
"image": "www.test.com",
"title": "test",
"user_id": null
}
}
我想使用 Breeze 将其放入 Knockout 可观察量中。我认为我需要一个自定义的 jsonResultsAdapter 。我试图遵循埃德蒙兹的例子,但我承认我并没有真正理解它。
var jsonResultsAdapter = new breeze.JsonResultsAdapter({
name: "test",
extractResults: function (data) {
var results = data.results;
if (!results) throw new Error("Unable to resolve 'results' property");
return results;
},
visitNode: function (node, parseContext, nodeContext) {
// Make parser
if (node.objects) {
return { entityType: "Pin" }
}
}
});
var dataService = new breeze.DataService( {
serviceName: "api/",
hasServerMetadata: false,
jsonResultsAdapter: jsonResultsAdapter,
});
var manager = new breeze.EntityManager( {
dataService: dataService
});
var query = new breeze.EntityQuery.from("pin");
manager.executeQuery(query).then(function(data){
ko.applyBindings(data);
}).fail(function(e) {
alert(e);
});
但是在executeQuery函数内部失败并显示一条消息:
Error: Unable to locate a 'Type' by the name: 'Pin'. Be sure to execute a query or call fetchMetadata first.
我以为我刚刚做到了。我在这里做错了什么?
编辑
function initialize(metadataStore) {
var DT = breeze.DataType; // alias
metadataStore.addEntityType({
shortName: "Pin",
namespace: "test",
dataProperties: {
creator: { dataType: DT.String },
id: { dataType: DT.Int64, isPartOfKey: true },
image: { dataType: DT.String },
title: { dataType: DT.String },
modelLinks: { dataType: DT.Int64 }
},
});
}
已经部分弄清楚了。需要添加一个元数据存储来描述返回的数据类型。但现在我明白了
Error: You cannot apply bindings multiple times to the same element.
最佳答案
我怀疑您的 JsonResultsAdapter
没有执行您认为应该执行的操作。您应该调试它以查看发生了什么。
还要检查返回到查询成功回调的数据。 data.results
中的对象对您来说合适吗?他们有 entityAspect
属性吗? entityType
属性?如果不是,数据就不会成为实体,我认为它们也不会有可观察的属性。
我相信您会将问题追溯到 visitNode
方法。当您在 node.objects
上获得匹配项时,我预测节点本身将如下所示:
{
"num_results": 2,
"objects": [
{
"creator": null,
"id": 1,
"image": "www.test.com",
"title": "test",
"user_id": null
},
...
]
}
您的回应
return { entityType: "Pin" }
似乎是在告诉 Breeze,这整个事情应该被视为 Pin
类型的数据。
事实显然并非如此。 Pin
数据位于objects
数组内部。
您实际上想要匹配这些数据。您可以通过类似的测试来做到这一点
if (node.id && node.title) {
return { entityType: ... } // see below
}
或者类似的东西。
风险在于此类测试可能会与 Pin
以外的某些类型的数据匹配。如果您的服务器可以使用数据序列化类型指示器,那么事情就会变得容易得多。
We did this in our rails sample. We added a
$type
property to each entity object serialized to a Breeze client and set it to the name of the type. That made it easy to identify the node.
您必须返回EntityType
而不是类型的名称
看看 "webApi" DataServiceAdapter 的实现.
您将看到没有返回类型的名称。您返回匹配的 EntityType
。
您需要类似这样的代码:
var type = mappingContext.entityManager.metadataStore.getEntityType('Pin', true);
return { entityType: type }
我确信您可以想象一种更有效的方法来缓存此类型对象,这样您就不必在每次访问节点时都费力地获取它。
为什么要指定类型的命名空间?
您使用命名空间“test”定义了 Pin
类型。为什么?这是服务器上的命名空间吗?还是你刚刚编造出来的?如果你没有的话,你就不需要一个。它只会增加不必要的复杂性。
你可能会侥幸逃脱:
var DT = breeze.DataType; // alias
metadataStore.addEntityType({
shortName: "Pin",
dataProperties: {
creator: { }, // string is the default
id: { dataType: DT.Int64, isPartOfKey: true },
image: { },
title: { },
modelLinks: { dataType: DT.Int64 }
},
});
更好的extractResults函数?
您还可以考虑改进 extractResults
方法,以便它立即消除无关的内容。为什么不像这样直接进入对象
级别呢?
extractResults: function (data) {
var results = data.results && data.results.objects;
if (!results) throw new Error("Unable to resolve 'results.objects' property");
return results;
}
关于knockout.js - 简单的 JSON 和 Breeze 导致错误为 "call fetchMetadata first",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28569338/