【问题标题】:Adding multiple list views to same resource - Admin-On-Rest向同一资源添加多个列表视图 - Admin-On-Rest
【发布时间】:2017-05-23 14:45:46
【问题描述】:

我有一个故事资源,我想根据故事状态以不同方式为同一用户显示该资源

status = NEW 的故事应该与 List1 一起显示

states = APPROVED 等的故事需要显示为 List2(我需要显示故事的不同属性)

如何使用 Admin-On-Rest 实现这一目标?

两次添加相同的资源(如下)并为两者分配不同的列表视图只会导致第一个被显示而第二个被忽略

<Resource name="tales" list={EditorAssignedList} edit={EditTale} options={{ label: 'Assigned Tales' }}/>
<Resource name="tales" list={EditorTaleTrack} options={{ label: 'Your Tales' }}/>

记录了以下错误。

flattenChildren(...): Encountered two children with the same key, `1:$tales`. Child keys must be unique;

关于如何将唯一键注入资源的任何策略。

【问题讨论】:

    标签: admin-on-rest


    【解决方案1】:

    如果您还想通过不同的列表菜单向同一路线添加 CRUD 功能,上述答案并不是那么有用。如果您有 2 个带有 CRUD 组件的列表视图 List1 和 List2。从 List2 输入编辑(例如)并点击保存,您将被重定向到 List1

    更广泛的解决方案是为您的 REST 客户端创建一个自定义包装器。 灵感来自下方。 https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload

    就我而言,它看起来像这样。

    我在 App.js 中创建了一个虚拟资源“trackTale”。 restWrapper.js 中的

    const RESTWrapper = requestHandler => (type, resource, params) => {
    
          if (type === 'GET_LIST' && resource === 'trackTale') {
            const page =  params.pagination.page
            const perPage = params.pagination.perPage
            const {field, order} = params.sort
            const query = {}
            query['where'] = {...params.filter}
            if (field) {query['order'] = [field + ' ' + order]}
            if (perPage > 0) {
                query['limit'] = perPage;
                if (page >= 0) {
                    query['skip'] = (page - 1) * perPage
                }
            }
            //Key part here hardcoding the tales route to trackTale
    
    const url = config.host + '/' + 'tales?' +  queryParameters({filter: JSON.stringify(query)})
            const options = {};
            options.user = {authenticated: true}
            options.user.token = localStorage.getItem('token');
            options.method = 'GET';
            return fetchUtils.fetchJson(url, options)
              .then((response) => {
                const {headers, json} = response;
                //admin on rest needs the {data} key
                return {data: json,
                        total: parseInt(headers.get('x-total-count').split('/').pop(), 10)}
            })
        }
    }
    
    
    //below function is very very specific to how loopback.js expects to recieve REST queries. Please customize it for your API needs
    const queryParameters = data => Object.keys(data)
        .map(key => [key, data[key]].map(encodeURIComponent).join('='))
        .join('&');
    

    这适用于所有情况。如果您的不同路线没有 CRUD,仍然可以创建自定义菜单。

    【讨论】:

    • 您的代码中的configqueryParameters 是什么?我假设 fetchUtils 来自 admin-on-rest?
    • Config 是我的本地配置,而 queryParameters 是我忘记包含在上面的函数。我现在添加它。 fetchUtils 是从 AOR 导入的。
    【解决方案2】:

    只保留一种资源。创建一个包含 2 个条目的自定义菜单,将过滤器传递给 url 参数。

    然后在 TalesList 组件中,根据您的参数显示正确的版本组件

    【讨论】:

    • 已按照文档中的建议创建了一个菜单元素。但是,需要澄清您提到的两点。 1)如何将过滤器参数从菜单组件传递给资源? 2)如何访问从列表视图中单击的菜单项(基本上我如何访问已点击的链接以及要显示的视图)
    • 1) 查看设置了过滤器的普通列表视图页面的 url。这应该给你你需要的参数的名称。然后只需按照Link 组件上的反应路由器文档 2) 也许aor-dependent-input 插件可以帮助您。我还没有在视图上测试它。如果这不起作用,我会看看我们如何升级它以支持视图。
    • 好的。会得到这个并告诉你。
    【解决方案3】:

    在@Gildas 的大力帮助下解决了

    这个问题解决了

    1) 创建自定义菜单组件

    const linkData = {
      pathname: "/tales",
      hash: "trackTales"
    }
    
    export default ({ resources, onMenuTap, logout }) => {
      return (
        <div>
          <MenuItem containerElement={<Link to="/tales" />} primaryText="Tales For Edit" onTouchTap={onMenuTap} />
          <MenuItem containerElement={<Link to={ linkData } />} primaryText="Track Tales" onTouchTap={onMenuTap} />
          {logout}
        </div>
      )
    }
    

    React Router 的链接组件接受对象作为参数。这些作为道具传递给下游组件。

    export const EditorAssignedList = (props) => {
      return taleViewJuggler(props)
    }
    

    juggler 函数读取道具并根据道具创建自定义视图。链接组件正在将数据传递给道具中的“位置”键。

    const taleViewJuggler = (props) => {
      let viewName = props.location.hash
      let component;
      switch (viewName) {
        case "case1":
          component = (
            <ListView1 />
          )
          break;
        case "#case2":
          component = ( < ListView2 /> )
          break;
      }
      return component
    }
    

    【讨论】:

    • 太棒了 :) 我认为依赖输入插件对视图不起作用?
    • 我没试过 TBH。我对您最初的建议有所了解,但一直在努力寻找一种将自定义道具从菜单传递到上面的开关组件的方法。再次感谢一切。也非常感谢 Admin on Rest。在我完成我的项目并获得报酬后,我非常想为团队中的你们赞助一杯啤酒:)
    • Ok :) 仅供参考,我刚刚发布了一个新版本的 aor-dependent-input 插件,它现在为视图提供了一个 DependentField 组件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多