ember.js的rest JSON递归嵌套在同一个模型中
ember.js rest JSON recursively nested with same model
下面是我从REST端点获得的JSON示例。我需要从subcategories
数组创建一个树状结构,正如您所看到的,这些数组是递归嵌套的。
我搜索并尝试了将近一周,但无法找到一个完全有效的解决方案——到目前为止,我得到的最好的解决方案是,子类别既作为其父子类别的子类别(根据需要)出现,也作为正常的顶级节点出现,这显然是我不想要的。
我的问题很简单:我该如何建模,以便ember.js能够创建所需的树状结构?
我不认为这对一个有经验的ember用户来说很困难,但和通常的ember文档一样,它既不是最新的,也没有涵盖更多琐碎的概念。
无论我往哪里看,这种嵌套结构的概念似乎都是陌生的(我发现的所有嵌套都有不同的类型,但这正是我不需要的)。JSON格式是不可变的,我必须按原样处理它。
我用创建了我的项目-ember cli 0.2.7-ember.js 1.13.0-成员数据1.13.4使用DS.RESTAdapter和DS.RESTSerializer
{
"id": 28,
"hassubcategories": true,
"CategoryName": "By Asset Type",
"subcategories": [
{
"id": 29,
"CategoryName": "Images",
"hassubcategories": true,
"subcategories": [
{
"id": 30,
"CategoryName": "Illustrations",
"hassubcategories": false
},
{
"id": 31,
"CategoryName": "Pictures",
"hassubcategories": true,
"subcategories": [
{
"id": 61,
"CategoryName": "BMP",
"hassubcategories": false
},
{
"id": 32,
"CategoryName": "EPS",
"hassubcategories": false
}
]
}
]
},
{
"id": 73,
"CategoryName": "InDesign (related)",
"hassubcategories": false
}
]
}
这应该在模板中呈现为树状列表图像-插图--BMP--EPS不设计(相关)
谢谢你的帮助。
编辑2015-07-17:我仍然没有接近一个动态的解决方案,但目前(谢天谢地,级别限制在两个)我很高兴创建一个子类别模型和侧载。我遍历有效负载,获取每个子类别(第二级)的id,并将该子类别移动到列表中。我的序列化程序子类别:
import DS from 'ember-data';
import ember from 'ember';
export default DS.RESTSerializer.extend({
isNewSerializerAPI: true,
primaryKey: 'id',
normalizeHash: {
subcategories: function(hash) {
if(ember.get(hash, 'hassubcategories') && !ember.isEmpty(ember.get(hash, 'subcategories'))) {
var ids = [];
ember.get(hash, 'subcategories').forEach(function(cat){
ids.push(ember.get(cat, 'id'));
});
hash.children = ids;
}
return hash;
}
},
extractMeta: function(store, type, payload) {
if (payload && payload.subcategories) {
var subs = [];
var subs2 = [];
payload.subcategories.forEach(function(cat){
if(cat['hassubcategories']) {
var subsubs = cat['subcategories'];
subs.addObject(cat);
subs2.addObjects(subsubs);
} else {
subs.addObject(cat);
}
});
payload.subcategories = subs;
payload.subsubcategories = subs2;
}
delete payload.id; // keeps ember data from trying to parse "id" as a record (subcategory)
delete payload.hassubcategories; // keeps ember data from trying to parse "hassubcategories" as a record (subcategory)
delete payload.CategoryName; // keeps ember data from trying to parse "CategoryName" as a record (subcategory)
delete payload.ParentID; // keeps ember data from trying to parse "ParentID" as a record (subcategory)
}
});
和模型子类别:
import DS from 'ember-data';
export default DS.Model.extend({
CategoryName: DS.attr('string'),
hassubcategories: DS.attr('boolean'),
children: DS.hasMany('subsubcategories', {async: false })
});
子类别:
import DS from 'ember-data';
export default DS.Model.extend({
CategoryName: DS.attr('string'),
hassubcategories: DS.attr('boolean'),
});
也许它对某人有帮助,也许我甚至得到了一个如何真正动态地做到这一点的提示。
如果您不介意的话,我将在不显示太多代码的情况下漫谈解决方案…:D
在EmberData(我假设您正在使用它)中,存储包含平面集合中某个类型的所有对象(概念上)。每个对象都通过关键字(id
)进行检索。Ember Data提供关系属性以对hasMany
或belongsTo
关系进行建模。因此,要在树结构中连接这些对象,您将有一个从父节点到其子节点的hasMany
:
App.Category = Ember.Model.extend({
name: DS.attr(),
subcategories: DS.hasMany('category'),
parent: DS.belongsTo('category')
});
因此,在上面的JSON示例中,假设您有这样的Category模型记录:
[{
id: 28,
name: "By Asset Type",
subcategories: [ 29, 73 ],
parent: null
}, {
id: 29,
name: "Images",
subcategories: [ 30, 31 ],
parent: 28
}, {
id: 73,
name: "InDesign (related)",
subcategories: [],
parent: 28
}, {
// ... etc ...
因此,您可以从这个对象数组中看到,它不是物理嵌套的,而是通过ID在逻辑上嵌套的如果您的JSON看起来是这样的,它可以由RESTAdapter
处理,一切都很好。(我希望你在这一点上同意并点头)。问题是,正如您所说,您的JSON是"不可变的",我认为这意味着格式不会改变。
Serializer
救援!通过创建一个自定义的CategorySerializer
(它扩展了RESTSerializer
),您可以覆盖extractArray
和extractSingle
函数,将JSON有效负载扁平化为一个数组,如上所示。我将把压平有效负载的代码留给读者练习。:)
幸运的是,您可以一次获得树中的所有数据,而不必处理中间REST调用和承诺解析。这当然是可行的,但它的异步性质使它有点棘手。
一些轻阅读:
- 将应用程序连接到REST服务
RESTSerializer
API
您的下一个问题可能是(对我来说一直是这样),如何使树中的每个节点响应其自己的URL(/categies/61),并将其与其祖先和兄弟姐妹一起显示在上下文中。
作为这个问题的更新答案,现在可以通过用DS.EmbeddedRecordsMixin
扩展DS.JSONSerializer
来实现。
例如,包含具有无限嵌套类别的subcategories
数组的category
模型将如下所示:
// app/model/category.js
import Ember from "ember";
import Model from "ember-data/model";
import attr from "ember-data/attr";
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
name: attr(),
subcategories: hasMany('category', { inverse: 'parent' }),
parent: belongsTo('category', { inverse: 'subcategories' })
});
您的application
适配器应该与以下类似:
// app/adapters/application.js
import DS from "ember-data";
import config from "../config/environment";
import Ember from "ember";
export default DS.RESTAdapter.extend({
});
您的application
序列化程序应该类似于以下内容:
// app/serializer/application.js
import DS from 'ember-data';
export default DS.JSONSerializer.extend({
});
最后,您的category
序列化程序是这样的:
// app/serializers/category.js
import ApplicationSerializer from './application';
import DS from 'ember-data';
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin,{
attrs: {
subcategories: {
serialize: 'records',
deserialize: 'records'
}
}
});
您的型号的此设置在此处记录为Reflexive Inverses
:https://guides.emberjs.com/v2.11.0/models/relationships/#toc_reflexive-关系
EmbeddedRecordsMixin
的文档可在此处找到:http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html
这应该允许嵌套的响应使用EmberData开箱即用。这让一切对我来说都很神奇。
希望这能帮助到别人。
祝你好运。
- 在VanillaJS中模拟模型双向数据绑定
- 为集合分配大量的模型弹药
- 如何使用backbone.js从集合中获取模型名称
- 在同一个服务工作者中处理service-worker.js有任何影响吗
- 为什么 .focus() 不起作用,而 .css(“color”,“red”) 在同一个选择器上起作用
- 骨干模型默认值-todos.js示例中不必要的代码
- EmberJS中支持单字母单词模型
- 2个backbone.js集合,具有相同的模型,但排序顺序不同
- 将不在模型中的数据返回到mvc控制器
- 如何在视图模型contet更新更新上调用Jquery函数
- 如何使用Javascript客户端对象模型检索Sharepoint 2010列表项权限
- 我应该如何检查主干.主干.模型更改时查看
- Ext.js从json构建模型关系的问题
- 如何使ng中的每个指令重复以共享同一个ng模型
- 若同一个控制器在一个页面中使用两次,则停止反映彼此的模型
- Angular.js:从同一个ng模型中获取不同形式的{display.value}}和$scope.value
- 同一个ActiveForm上的多个模型
- Angular.JS:视图共享同一个控制器,当改变视图时,模型数据会重置
- 不能将同一个模型添加到一个集合中两次
- ember.js的rest JSON递归嵌套在同一个模型中