Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.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
Angular RXJS 6:数组的递归筛选。。使用异步筛选器_Angular_Asynchronous_Filter_Rxjs - Fatal编程技术网

Angular RXJS 6:数组的递归筛选。。使用异步筛选器

Angular RXJS 6:数组的递归筛选。。使用异步筛选器,angular,asynchronous,filter,rxjs,Angular,Asynchronous,Filter,Rxjs,我需要过滤对象的递归数组。 每个对象表示一个webapp路由/url。此url可以限制为某个角色(权限=true | false),也可以不限制,并且每个url都可以有子url。。。递归地 编辑:复杂的部分是过滤需要一个异步函数调用(我在我的项目中有这个特定的需求)。 这就是为什么我试着用RXJS实现它,但我可以用标准数组函数+async/await实现它 我还借此机会学习了更多的rxjs,这就是为什么我想要一个面向rxjs的答案(这是一个处理异步的好方法?)。谢谢 具有此阵列: [

我需要过滤对象的递归数组。 每个对象表示一个webapp路由/url。此url可以限制为某个角色(权限=true | false),也可以不限制,并且每个url都可以有子url。。。递归地

编辑:复杂的部分是过滤需要一个异步函数调用(我在我的项目中有这个特定的需求)。 这就是为什么我试着用RXJS实现它,但我可以用标准数组函数+async/await实现它

我还借此机会学习了更多的rxjs,这就是为什么我想要一个面向rxjs的答案(这是一个处理异步的好方法?)。谢谢

具有此阵列:

[
      {
        id: 'level 1.1',
        permission: true,
        children: [
          {
            id: 'level 2.1',
            permission: false,
            children: [
              {id: 'level 3.1'}
            ]
          },
          {
            id: 'level 2.2',
            permission: true,
            children: [
              {id: 'level 3.2'}
            ]
          }
        ]
      },
      {
        id: 'level 1.2'
      },
      {
        id: 'level 1.3',
        permission: false
      }
    ]
我需要对其进行过滤,使其具有如下输出(仅保留没有权限或真实的条目:

[
      {
        id: 'level 1.1',
        permission: true,
        children: [
          {
            id: 'level 2.2',
            permission: true,
            children: [
              {id: 'level 3.2'}
            ]
          }
        ]
      },
      {
        id: 'level 1.2'
      }
    ]
我尝试的方法在没有递归(注释代码)的情况下工作,因此成功过滤了第一级,但我不知道如何添加递归:

// simplified ASYNC filter function
promiseMe(x) {
    return Promise.resolve().then(() => {
      return x.permission === undefined || x.permission === true
    });
}

// recursive function
const recursive = arr => {
    return from(arr).pipe(
        mergeMap(entry => from(this.promiseMe(entry)).pipe(
            tap(y => console.log(y)),
            filter(Boolean),
            mapTo(entry),
            tap(console.log),
            mergeMap(item => {
                // here I'm lost
                // I need to affect the result of my async recursive function to item.children : 
              /*return recursive(item.children).pipe(
                  tap(res => {
                    console.log('RES', item, res)
                    item.children = res;
                  })
                );*/

                return of(item);
            })
        )),
        toArray()
    )
};

// main call
recursive(arr).subscribe(x => console.log('finally', x, JSON.stringify(x)))

在这里摆弄:

我不明白为什么需要RxJS来处理列表

我建议这项实施:

const source = [
    {
      id: 'level 1.1',
      permission: true,
      children: [
        {
          id: 'level 2.1',
          permission: false,
          children: [
            {id: 'level 3.1'}
          ]
        },
        {
          id: 'level 2.2',
          permission: true,
          children: [
            {id: 'level 3.2'}
          ]
        }
      ]
    },
    {
      id: 'level 1.2'
    },
    {
      id: 'level 1.3',
      permission: false
    }
];

const isAllow = item => {
  return item.permission === undefined || item.permission;
};

const filtering = (list) => {
  const listing = [];
  list.forEach(item => {
    // If current one have permission.
    if(isAllow(item)) {
      // If he have child, let process it recursively.
      if(item.children && item.children.length > 0) {
        item.children = filtering(item.children);
      }
      // Add current on to whitelisted.
      listing.push(item);
    }
  });
  return listing;
};

console.log(filtering(source));
如果您想在rxjs流上打开此列表,只需使用
map

of(source).pipe(map(source => filtering(source))).subscribe(console.log)
编辑一个: 基于澄清,我已经以可观察的方式完成了上述代码

目标是具有可观察的工厂功能(这里是
allownly$
),它:

  • 创建当前数组的每个项都将在其中广播的流
  • concatMap
    此项包含ajax请求
  • 筛选不允许的项
  • concatMap
    再次新增
    combinelatetest
    ,它是当前项和
    allowOnly$
    递归调用的组合,所有子项都作为参数
  • toArray
    将当前项目流转换回单个广播,所有项目合并到阵列上

const dummyAjaxRequest = (item) => {
  return of({
      ...item,
      permission: (item.permission === undefined || item.permission)?true:false
      });
}

const allowOnly$ = items => {
  return from(items).pipe(concatMap(item => {
    return from(
      /**
       * Perform your ajax request here to find what's is allow or not.
       */
      dummyAjaxRequest(item)
    ).pipe(
      /**
       * Exclude what is not allowed;
       */
      filter(item => item.permission),
      concatMap(item => {
        /**
         * If we have child, perform recursive.
         */
        if (item.children) {
          /**
           * combine child and parent.
           */
          return combineLatest(
            allowOnly$(item.children), // Recursive call.
            of(item)
          ).pipe(map(i => {
            return {
              ...i[1], // all property of current,
              children : [...i[0]] // Create new array base on allowed childrens.
            };
          }))
        }
        else {
          /**
           * No child, return simple observable of current item.
           */
          return of(item);
        }
      })
    );
  }), toArray()); // transform stream like --|-|-|-> to --[|,|,|]->
};

of(source).pipe(concatMap(items => {
  return allowOnly$(items);
})).subscribe(console.log);
重要提示:所有
mergeMap
都切换到
concatMap
,以尊重原始列表顺序,而不是混淆所有首先有ajax请求答案的项目


我不明白为什么需要RxJS来处理列表

我建议这项实施:

const source = [
    {
      id: 'level 1.1',
      permission: true,
      children: [
        {
          id: 'level 2.1',
          permission: false,
          children: [
            {id: 'level 3.1'}
          ]
        },
        {
          id: 'level 2.2',
          permission: true,
          children: [
            {id: 'level 3.2'}
          ]
        }
      ]
    },
    {
      id: 'level 1.2'
    },
    {
      id: 'level 1.3',
      permission: false
    }
];

const isAllow = item => {
  return item.permission === undefined || item.permission;
};

const filtering = (list) => {
  const listing = [];
  list.forEach(item => {
    // If current one have permission.
    if(isAllow(item)) {
      // If he have child, let process it recursively.
      if(item.children && item.children.length > 0) {
        item.children = filtering(item.children);
      }
      // Add current on to whitelisted.
      listing.push(item);
    }
  });
  return listing;
};

console.log(filtering(source));
如果您想在rxjs流上打开此列表,只需使用
map

of(source).pipe(map(source => filtering(source))).subscribe(console.log)
编辑一个: 基于澄清,我已经以可观察的方式完成了上述代码

目标是具有可观察的工厂功能(这里是
allownly$
),它:

  • 创建当前数组的每个项都将在其中广播的流
  • concatMap
    此项包含ajax请求
  • 筛选不允许的项
  • concatMap
    再次新增
    combinelatetest
    ,它是当前项和
    allowOnly$
    递归调用的组合,所有子项都作为参数
  • toArray
    将当前项目流转换回单个广播,所有项目合并到阵列上

const dummyAjaxRequest = (item) => {
  return of({
      ...item,
      permission: (item.permission === undefined || item.permission)?true:false
      });
}

const allowOnly$ = items => {
  return from(items).pipe(concatMap(item => {
    return from(
      /**
       * Perform your ajax request here to find what's is allow or not.
       */
      dummyAjaxRequest(item)
    ).pipe(
      /**
       * Exclude what is not allowed;
       */
      filter(item => item.permission),
      concatMap(item => {
        /**
         * If we have child, perform recursive.
         */
        if (item.children) {
          /**
           * combine child and parent.
           */
          return combineLatest(
            allowOnly$(item.children), // Recursive call.
            of(item)
          ).pipe(map(i => {
            return {
              ...i[1], // all property of current,
              children : [...i[0]] // Create new array base on allowed childrens.
            };
          }))
        }
        else {
          /**
           * No child, return simple observable of current item.
           */
          return of(item);
        }
      })
    );
  }), toArray()); // transform stream like --|-|-|-> to --[|,|,|]->
};

of(source).pipe(concatMap(items => {
  return allowOnly$(items);
})).subscribe(console.log);
重要提示:所有
mergeMap
都切换到
concatMap
,以尊重原始列表顺序,而不是混淆所有首先有ajax请求答案的项目


感谢您的帮助。我编辑了我的答案。关键是我的筛选需要异步(我添加了promise函数),这就是我尝试使用rxjs的原因。。这+我想学习如何使用rxjs概念,这也是我失去感谢您帮助的原因。我编辑了我的答案。关键是我的筛选需要异步(我添加了promise函数),这就是我尝试使用rxjs的原因。+事实上,我想学习如何使用rxjs概念,而这正是我失去的地方,我仍然对您迄今为止试图实现的目标感到困惑。您能描述一下您的功能流程吗?听起来您有嵌套的对象,但没有
权限
字段,并且您必须实现ajax请求询问这个标志,然后用这些新信息过滤你的原始列表。另一个问题:在进行任何处理之前,是否可以将列表展开?你所描述的是正确的。不可能展开,在我看来,在rxjs中构建一个组=>子菜单并不是那么自然的。有一个操作符叫做
expand
用于满足您的需要。我不久前写了一个类似问题的答案,请检查:这也是不可能的,但我强烈建议您避免多次请求授权。对我来说,您应该解析您的对象并搜索每个需要检查的项,然后执行单个请求,再次解析您的对象并设置授权标志。嗨,Cétia,我仍然不知道你到目前为止试图实现什么。你能描述一下你的功能流程吗?听起来你有没有
权限
字段的嵌套对象,你必须实现ajax请求来请求这个标志,然后用这个新信息过滤你的原始列表。另一个任务ion:在进行任何处理之前,是否可以将列表展平?您所描述的是正确的。不可能展平,在我看来,在rxjs中构建一个组=>子菜单Cursion并不是那么自然。有一个名为
expand
的操作符用于满足您的需要。有一段时间,我为类似的问题写了一个答案ago,check out:这也是不可能的,但我强烈建议您避免多次请求授权。对于我来说,您应该解析您的对象并搜索每个需要检查的项目,然后执行单个请求,再次解析您的对象并设置授权标志。