我有一个API端点,可以像这样吐出简单的JSON:
{
"num_results": 2,
"objects": [
{
"creator": null,
"id": 1,
"image": "www.test.com",
"title": "test",
"user_id": null
}
}
我想使用Breeze将其放入Knockout observables。我认为我需要一个自定义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函数中失败并带有消息:
错误:无法通过名称找到“类型”:'Pin'。请务必先执行查询或调用fetchMetadata。
我以为我刚刚那样做了。我在这做错了什么?
修改
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 }
},
});
}
部分弄清楚了。需要添加metadataStore来描述返回的数据类型。但现在我得到了
错误:您无法多次将绑定应用于同一元素。
答案 0 :(得分:2)
我怀疑你的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
以外的某些类型的数据匹配。如果您的服务器可以使用数据序列化类型指示器,那么它将更容易 。
我们在our rails sample中完成了此操作。我们added a
$type
property将每个实体对象序列化为Breeze客户端并将其设置为该类型的名称。这使得识别节点变得容易。
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
方法,以便它立刻摆脱无关紧要的东西。为什么不直接进入这样的objects
级别?
extractResults: function (data) {
var results = data.results && data.results.objects;
if (!results) throw new Error("Unable to resolve 'results.objects' property");
return results;
}