Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/435.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript ember.js rest JSON递归嵌套在同一个模型中_Javascript_Json_Rest_Recursion_Ember.js - Fatal编程技术网

Javascript ember.js rest JSON递归嵌套在同一个模型中

Javascript ember.js rest JSON递归嵌套在同一个模型中,javascript,json,rest,recursion,ember.js,Javascript,Json,Rest,Recursion,Ember.js,下面是我从REST端点获得的JSON示例。我需要从子类别数组中创建一个树状结构,如您所见,这些数组是递归嵌套的 我搜索并尝试了将近一个星期,但无法找到一个完全有效的解决方案——到目前为止,我得到的最好结果是子类别既作为其父子类别的子类别出现(如所需),也作为正常的顶级节点出现,这显然是我不想要的 我的问题很简单:如何对此建模,以便ember.js能够创建所需的树状结构 我不认为这对经验丰富的ember用户来说很难,但像往常一样,ember的文档既不是最新的,也不涵盖更多的琐碎概念 无论我在哪里看

下面是我从REST端点获得的JSON示例。我需要从
子类别
数组中创建一个树状结构,如您所见,这些数组是递归嵌套的

我搜索并尝试了将近一个星期,但无法找到一个完全有效的解决方案——到目前为止,我得到的最好结果是子类别既作为其父子类别的子类别出现(如所需),也作为正常的顶级节点出现,这显然是我不想要的

我的问题很简单:如何对此建模,以便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
    }
]
}

这应该在模板中呈现为树状列表 图像 -插图 --骨形态发生蛋白 --每股收益 Indesign(相关)

谢谢你的帮助

编辑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'),
});
模型呢 子类别:

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'),
});
子类别:

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

在Ember数据(我假设您正在使用)中,存储区包含平面集合中类型的所有对象(概念上)。每个对象都通过键(
id
)检索。余烬数据为模型a
具有许多
属于
关系提供关系属性。因此,要在树结构中连接这些对象,您将有一个从父节点到其子节点的
hasMany

App.Category = Ember.Model.extend({
    name: DS.attr(),
    subcategories: DS.hasMany('category'),
    parent: DS.belongsTo('category')
});
因此,在上面的JSON示例中,假设您有如下类别模型记录:

[{
  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 ...
// 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' })
});
因此,您可以从这个对象数组中看到,它不是物理嵌套的,而是通过ID进行逻辑嵌套的。如果您的JSON看起来像这样,那么可以通过
RESTAdapter
进行处理,一切都很好。(我希望在这一点上你同意并点头)。问题是,正如您所说,您的JSON是“不可变的”,我认为这意味着格式不会改变

Serializer
救命!通过创建自定义的
CategorySerializer
(它扩展了
RESTSerializer
),您可以覆盖
extractArray
extractSingle
函数,将JSON负载展平到一个数组中,如上所示。我将把压平有效载荷的代码留给读者作为练习。:)

幸运的是,您一次获得了树中的所有数据,而不必处理中间REST调用和承诺解析。这当然是可行的,但它的异步特性使它有点棘手

一些轻松的阅读:


您的下一个问题可能是(对我来说也是如此),如何使树中的每个节点响应其自己的URL(/categories/61),并在其祖先和兄弟姐妹的上下文中显示它。

作为此问题的更新答案,现在可以通过使用
DS.EmbeddedRecordsMixin
扩展
DS.JSONSerializer
来实现这一点

例如,包含具有无限嵌套类别的
子类别
数组的
类别
模型如下所示:

[{
  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 ...
// 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' })
});
而您的
应用程序
适配器的外观应该与此类似:

// app/adapters/application.js
import DS from "ember-data";
import config from "../config/environment";
import Ember from "ember";

export default DS.RESTAdapter.extend({

});
// app/serializer/application.js
import DS from 'ember-data';

export default DS.JSONSerializer.extend({

});
而您的
应用程序
序列化程序的外观应该与此类似:

// app/adapters/application.js
import DS from "ember-data";
import config from "../config/environment";
import Ember from "ember";

export default DS.RESTAdapter.extend({

});
// app/serializer/application.js
import DS from 'ember-data';

export default DS.JSONSerializer.extend({

});
最后,您的
类别
序列化程序如下:

// 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'
    }
  }
});
您的模型的此设置记录为
自反反转
,如下所示:

可在此处找到
EmbeddedRecordsMixin
的文档:

这应该允许嵌套的响应工作,使用Ember数据开箱即用。这让我觉得一切都很神奇

希望这对别人有帮助


祝你好运。

谢谢steve,但我真的不明白在ember数据中如何实现嵌套(即父子关系)。那么,这个问题在你的最后一句话中已经描述过了。在
extractArray
中展平数组的好方法是什么?