【问题标题】:Groupby Observable <Object[]> Angular 7Groupby Observable <Object[]> Angular 7
【发布时间】:2019-09-10 02:29:50
【问题描述】:

我正在尝试根据从 observable 返回的值对数组元素进行分组,并在视图上将这些组显示为不同的 &lt;mat-card&gt;

我有一个 in-memory-web-api-module,其中包含下面简化示例的类。

我还在学习 Angular,所以请原谅我的菜鸟

例如: in-memory-data.service.ts

export class InMemoryDataService implements InMemoryDbService {
createDb(){
const apps = [
{id: '1', app: 'app1', env_id:2, env:'DEV'},
{id: '2', app: 'app2' env_id:2, env:'DEV'},
{id: '4', app: 'app3' env_id:2, env:'DEV'},
{id: '5', app: 'app1' env_id:3, env:'Test'},
{id: '6', app: 'app2' env_id:3, env:'Test'},
{id: '7', app: 'app3' env_id:1, env:'PROD'},
];
return {apps}
}

应该为每个不同的应用程序值创建一个新的&lt;mat-card&gt;,而不是为每个应用程序值创建它现在正在做的事情。

这是我的代码。

applications.service.ts 编辑:

import { Injectable } from '@angular/core';
import { Apps } from './applications';
import { APPS } from './mock-applications';
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { MessagesService } from './messages.service';
import { catchError, map, switchMap, tap, groupBy, mergeMap } from 'rxjs/operators';

export class ApplicationsService {

private applicationUrl = 'api/apps';

constructor(private messageService: MessagesService, private http: HttpClient ) { }

getApps(): Observable<Apps[]> {
  return this.http.get<Apps[]>(this.applicationUrl)
    .pipe(
      groupBy(application=> application.app),
      mergeMap(obs => {
        retun obs.pipe(
          toArray(),
          map(apps => {
            return {id: obs.key, group: apps}
          })
        )
      }),
      toArray(),
      tap(_ => this.log('fetched apps')),
      catchError(this.handleError<Apps[]>('getApps', []))
    )
}

/*Type 'Observable<Apps[] | {}[]>' is not assignable to type 'Observable<Apps[]>'.
  Type 'Apps[] | {}[]' is not assignable to type 'Apps[]'.
    Type '{}[]' is not assignable to type 'Apps[]'.
      Type '{}' is missing the following properties from type 'Apps': guid, mots_spi_indicator, mots_sox_indicator, mots_pci_indicator, and 42 more./*

getApp(id: string): Observable<Apps> {
  const url = `${this.applicationUrl}/${id}`;
  return this.http.get<Apps>(url).pipe(
    tap(_ => this.log(`fetched app guid=${id}`)),
    catchError(this.handleError<Apps>(`getApp guid=${id}`))
  );

}
}

home.component.ts

import { Component, OnInit } from '@angular/core';
import { Apps } from '../../applications'
import { APPS } from '../../mock-applications';
import { ApplicationsService } from 'src/app/applications.service';

export class HomeComponent implements OnInit {

  apps: Apps[];

  constructor(private appService: ApplicationsService) { }

  ngOnInit() {
    this.getApps();
  }

  getApps(): void{
    this.appService.getApps()
    .subscribe(apps =>  this.apps = apps);
  }

}

home.component.html

<h1>My Access</h1>
<app-app-search></app-app-search>

<div fxLayout="row wrap">
  <div *ngFor="let app of apps" fxFlex.gt-sm="25" fxFlex.gt-xs="50" fxFlex="100">

    <a routerLink="/detail/{{app.id}}">
      <mat-card class="card-widget mat-teal">
        <div mat-card-widget>
          <div mat-card-float-icon>
            <mat-icon>error</mat-icon>
          </div>
          <div class="pl-0">
            <h2 mat-card-widget-title>{{app.app}}</h2>
          </div>
        </div>
      </mat-card>
    </a>

  </div>
</div> 

我怎样才能使每个应用名称都放入它自己的组中?

【问题讨论】:

    标签: angular typescript rxjs angular7


    【解决方案1】:

    这是一种分组方式:

    export class AppComponent implements OnInit {
      apps$: Observable<any>;
      createDb() {
        const apps = [
          { id: '1', app: 'app1', env_id: 2, env: 'DEV' },
          { id: '2', app: 'app2', env_id: 2, env: 'DEV' },
          { id: '4', app: 'app3', env_id: 2, env: 'DEV' },
          { id: '5', app: 'app1', env_id: 3, env: 'Test' },
          { id: '6', app: 'app2', env_id: 3, env: 'Test' },
          { id: '7', app: 'app3', env_id: 1, env: 'PROD' },
        ];
        return from(apps)
      }
    
      ngOnInit() {
        this.apps$  = this.createDb().pipe(
          // Tell rx which property to group by
          groupBy(application => application.app),
          mergeMap(obs => {
            // groupBy returns a GroupedObservable, so we need to expand that out
            return obs.pipe(
              toArray(), 
              map(apps => {
                return {id: obs.key, group: apps}
              })
            )
          }),
          toArray(),
        )
      }
    }
    
    <div *ngFor="let app of apps$ | async">
      <h4>{{ app.id }}</h4>
      <ul>
        <li *ngFor="let item of app.group">{{ item | json }}</li>
      </ul>
    </div>
    

    输出:

    app1
      { "id": "1", "app": "app1", "env_id": 2, "env": "DEV" }
      { "id": "5", "app": "app1", "env_id": 3, "env": "Test" }
    app2
      { "id": "2", "app": "app2", "env_id": 2, "env": "DEV" }
      { "id": "6", "app": "app2", "env_id": 3, "env": "Test" }
    app3
      { "id": "4", "app": "app3", "env_id": 2, "env": "DEV" }
      { "id": "7", "app": "app3", "env_id": 1, "env": "PROD" }
    

    Stackblitz

    【讨论】:

    • 只有当它是自己的组件时才有效?它目前用于提供虚假的后端,因为现在没有从服务器获取数据。我有另一个服务,它返回一个可观察的应用程序。这就是我想按组分解应用程序的地方。我会尝试从你的 pipe() 那里 pippyback 看看它是怎么回事
    • 对于这个例子,是的,但我不会重新创建内存服务,安装材料等来显示 rxjs 逻辑:)
    • 好的,解决你的 rxjs 逻辑我添加了 groupBy 和 mergeMap 函数,如下面的示例,但是我收到了这个错误,请参见上面的编辑。我添加了一条评论,其中包含我看到的错误消息
    • getApps 函数的类型为Observable&lt;Apps[]&gt;,但现在返回的类型为Observable&lt;{id: string, group: Apps[]}[]&gt;
    • 也许我错过了什么。 getApps(): Observable { 仍然全部用红色下划线 :(
    【解决方案2】:

    为此使用 lodash

    npm install lodash
    
    import * as groupBy from "lodash/groupBy";
    

    ...

    getApps(): void{
        this.appService.getApps()
        .subscribe(apps => {
           var grouppedApps = groupBy(apps,"app");
           // You can do whatever you want now
         } );
      }
    

    【讨论】:

    • 谢谢让我试一试
    • 好的,这很完美。我这样做了,并且能够控制台记录输出,并按预期按应用程序拆分。那么现在如何使用上面的 html 模板在视图中显示它呢?我尝试弄乱一些值,但主页返回空白,没有应用程序。
    【解决方案3】:

    from() 运算符创建一个 fires the elements of the array and then terminates 的 observable。 toArray() 运算符 collects all source emissions and emits them as an array when the source completes. 因此,对于您没有要发出的一组固定值的用例,您不能使用 toArray()。但是,您可以将map 与来自lodash_.groupBy() 一起使用。这是我为这个特殊案例所做的:

      this.filteredMeetingList$ = this.sorting$.pipe(
      switchMap(sorting => this.meetingList$.pipe(
        // ...
        map(sMeetings => sMeetings.map(m => ({
          ...m,
          day: moment(m.startDateTime).format('DD. MMM'),
        }))),
      )),
      map(elem => _.groupBy(elem, 'day')),
     );
    

    【讨论】:

      猜你喜欢
      • 2018-10-24
      • 1970-01-01
      • 2018-05-09
      • 2019-03-30
      • 2016-12-18
      • 2018-01-31
      • 2019-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多