RxJS и ANGULAR: реструктурировать / переупорядочить данные json на основе определенного «ключа» с использованием RxJS - PullRequest
0 голосов
/ 29 сентября 2019

Я извлекаю эти данные JSON, которые представляют собой массив объектов, и мне нужно реструктурировать / переупорядочить их, чтобы можно было отобразить информацию в моем компоненте.

представить структуру:

[
  {
    "name": "Rahul",
    "class": 3,
    "gender": "M",
    "section": "B",
    "rollNumber": "1231",
    "sports": [
      "Badminton",
      "Chess"
    ],
    "age": 7
  },
  {
    "name": "Rajat",
    "class": 5,
    "gender": "M",
    "section": "C",
    "rollNumber": "123122",
    "sports": [
      "Chess"
    ],
    "age": 9
  },
]

требуемая структура:

class 4
   section A
       name
   section B
       name
class 5
   section A
       name
   section B
       name
.
.
.

Я пробовал это с использованием groupBy () и mergeMap () в rxjs здесь: пример 2

Это мой угловой сервис:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, from, of, zip, pipe } from 'rxjs';
import { groupBy, mergeMap, toArray, map, tap} from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class ConfigService {
  const studentURL = 'https://student-management-api-1u3cd4j7s.now.sh/students';

  constructor(private http: HttpClient) { }
  public getStudents(): Observable<any> {
    const studentList = this.http.get(this.studentURL);
    .tap(result => result.json());
    from(studentList)
    .pipe(
      groupBy(studentList => studentList.class),
      mergeMap(group => zip(of(group.key), group.pipe(toArray())))
    )
    .subscribe(console.log('studentList', studentList));
    return studentList;
  }
}

файл component.ts

import { Component, OnInit } from '@angular/core';

import { ConfigService } from '../config/config.service';

@Component({
  selector: 'app-class-component',
  templateUrl: './class-component.component.html',
  styleUrls: ['./class-component.component.css']
})
export class ClassComponentComponent implements OnInit {
  students: object;
  constructor(private data: ConfigService) {}

  ngOnInit() {
    this.data.getStudents().subscribe(data => {
      this.students = data;
      console.log(data);
    });
  }
}

компонент.HTML-файл

<div class='container'>
  <ul *ngFor="let student of students; let i = index">
    <h3> Class {{ student.class }}</h3>
    <li *ngFor="let section of students; let i = index">
      <h5> section {{ student.section}}</h5>
      <!-- <a href='#' *ngFor="let name of students">{{student.name}}</a> -->
    </li>
  </ul>
</div>

Я думаю, что было бы лучше реструктурировать / переупорядочить в самом сервисе после выборки.Не уверен, где я иду не так и чего мне не хватает.

1 Ответ

2 голосов
/ 29 сентября 2019

Шаг 1 : вы получите массив, который испускает весь массив для groupBy, чтобы работать, вам нужно выдать все значения, так что здесь с switchMap и из мы будем выдавать все записи массива

Шаг 2 : groupBy даст другую наблюдаемую величину, которую вам нужно объединить, чтобы увидеть сгруппированный результат.Все группы теперь будут выдавать значение

. В приведенном ниже примере могут быть 2 группы класса 3 и 5, поэтому конечный результат в вашей функции подписки будет вызываться дважды: одна с классом 3, другая с классом 5.

Шаг 3: Если вы хотите углубиться, повторите groupBy и объедините карту

this.http.get(this.studentURL).pipe(
  switchMap(val => from(val)),
  groupBy(studentList => studentList.class),
  mergeMap(group => group.pipe(toArray())),
  map(studentList => ({['class' + studentList[0].class]: studentList }))
)

Stackblitz: https://stackblitz.com/edit/rxjs-8jlvij?file=index.ts


Обновление 2: решение

Сервис :

public getStudents(): Observable<any> {
  return this.http.get<any[]>(this.studentURL)
  .pipe(
    switchMap(val => from(val)),
    groupBy(studentList => studentList.class),
    mergeMap(group => group.pipe(toArray())),
    map(studentList => ({
      [studentList[0].class]: studentList.reduce((sections, student) => ({...sections, [student.section]: [...(sections[student.section] || []), student]}), {})
    })),
    scan((response, studentList) => ({...response, ...studentList}), {})
  );
}

Компонент :

students$: Observable<any>; 
// you can hook up the observable here 
// in template you can use the the async pipe 
// to subscribe to the observable

ngOnInit() {
  this.students$ = this.service.getStudents();
}

Шаблон :

<div class='container'>
  <ul *ngFor="let classItem of students$ | async | keyvalue; let i = index">
    <li> Class {{ classItem.key }}</li>
      <ul>
        <li *ngFor="let sectionItem of classItem.value | keyvalue; let i = index">
          <h5> Section {{sectionItem.key}}</h5>
          <ul>
            <li><a href='#' *ngFor="let student of sectionItem.value ">{{student.name}}</a></li>
          </ul>
        </li>
      </ul>
  </ul>
</div>

Обновлен Stackblitz: https://stackblitz.com/edit/angular-tspamr

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...