代码之家  ›  专栏  ›  技术社区  ›  LatentDenis

在Angular/RXJS中将对象添加到对象数组的观察对象中?

  •  1
  • LatentDenis  · 技术社区  · 6 年前

    将对象添加到现有的可观察对象数组中。在DOM上进行这种反思是最后一步。

    NewObject.ts :

    export class NewObject {
      name: string;
      title: string;
    }
    

    这是 example.component.ts :

    import { Observable } from 'rxjs';
    import { Component, OnInit, Inject, EventEmitter } from '@angular/core';
    import { NewObject } from 'objects';
    
    @Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.css']
    })
    export class ExampleComponent implements OnInit {
    
      // Initializing the object array Observable from a service (step 1)
      readonly objects$: Observable<NewObject[]> = this.objectSvc.getAllObjects("objects").pipe(
        map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
        shareReplay(1)
      );
    
      constructor(
        private objectSvc: ObjectService
      ) { }
    
      ngOnInit() {
    
        somethingThatHappensToAdd = (response: any) => {
          let data = JSON.parse(response);
          data.forEach(x => {
            let obj: NewObject = { name: x.name, title: alterString(x.title) }
    
            // Here's where I'm trying to add the obj object into the already existing object array Observable
          });
        };
    
        somethingThatHappensToDelete = (response: any) => {
          let data = JSON.parse(response);
          data.forEach(x => {
            let obj: NewObject = { name: x.name, title: alterString(x.title) }
    
            // Here's where I'm trying to delete the obj object from the already existing object array Observable
          });
        };
    
      }
    }
    

    这是我的 example.component.html

    <div *ngFor="let o of objects$ | async">
       <p>{{ o.name }}</p>
       <p>{{ o.title}}</p>
    </div>
    

    这是我的服务 object.service.ts :

    import { Injectable } from '@angular/core';
    import { Observable, throwError, of } from 'rxjs';
    import { map, catchError } from 'rxjs/operators';
    import { ClientApi, ApiException, NewObject } from '../client-api.service';
    
    @Injectable({
      providedIn: 'root'
    })
    export class ObjectService {
    
      constructor(
        private clientApi: ClientApi
      ) { }
    
      getAllObjects(name: string): Observable<NewObject[]> {
        return this.clientApi.getAllObjects(name)
          .pipe(
            map((x) => x.result),
            catchError(err => {
              if (ApiException.isApiException(err)) {
                if (err.status === 404) {
                  return of<NewObject[]>(undefined);
                }
              }
              return throwError(err);
            })
          );
      }
    }
    

    在格式化响应之后 JSON obj 对象放入 objects$ 可观察并在UI上反映。

    BehaviorSubject 使这一切发生的因素。有人能告诉我们如何容易地做到这一点吗?

    0 回复  |  直到 6 年前
        1
  •  2
  •   Harun Yilmaz    6 年前

    您可以创建 BehaviorSubject 从中发出结果 somethingThatHappens() combineLatest() 将结果与来自服务的结果合并。

    objectsFromService$ = this.objectSvc.getAllObjects("objects").pipe(
        map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) })))
    );
    
    resultsArray = []
    resultsSubject = new BehaviorSubject(this.resultsArray);
    results$ = this.resultsSubject.asObservable()
    
    readonly objects$: Observable<NewObject[]> = combineLatest(
        this.results$,
        this.objectsFromService$
    ).pipe(
       map(([results, objects]) => ([...results, ...objects])),
       shareReplay(1)
    )
    
    
    somethingThatHappens = (response: any) => {
          let data = JSON.parse(response);
          data.forEach(x => {
            let obj: NewObject = { name: x.name, title: alterString(x.title) }
            this.resultsArray.push(obj)          
          });
          this.resultsSubject.next(this.resultsArray)
    };
    

    我创建了一个正在工作的stackblitz项目: https://stackblitz.com/edit/angular-jnngwh

    希望这能给你一个线索。

        2
  •  0
  •   adrisons    6 年前

    我觉得哈伦的回答很好( https://stackoverflow.com/a/60108390/1974681 )

    export class ExampleComponent implements OnInit {
    
        let objects$: Observable<NewObject[]>;
    
        constructor(
            private objectSvc: ObjectService
        ) { }
    
        private initializeObservable() {
            return this.objectSvc.getAllObjects("objects").pipe(
                map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
                shareReplay(1)
            );
        }
    
        private getObservableWithNewValues() {
            const response = callService();
            let array = [];
            let data = JSON.parse(response);
            data.forEach(x => {
                let obj: NewObject = { name: x.name, title: alterString(x.title) }
                array.push(obj);
            });
    
            // This creates an observable of the array
            return of(array);
        }
    
        ngOnInit() {
            const initialObservable = this.initializeObservable();
    
            const anotherObservable = this.getObservableWithNewValues();
    
            this.objects$ = concat(initialObservable, anotherObservable);
        }
    }
    

    参考文献:

        3
  •  0
  •   LatentDenis    6 年前

    解决方案1: https://stackblitz.com/edit/angular-rajvqq

    constructor(private myService: MyService){
      this.myService.getObjects().subscribe(x => this.somethingThatHappensToAdd(x));
    }
    
    resultsArray = []
    resultsSubject = new BehaviorSubject(this.resultsArray);
    
    readonly objects$: Observable<number[]> = combineLatest(
      this.resultsSubject,
    ).pipe(
      map(([results]) => ([...results])),
      shareReplay(1)
    )
    
    somethingThatHappensToAdd( arrayOfValues ) {
      arrayOfValues.forEach(x => {
        this.resultsArray.push(x)          
      });
      this.resultsSubject.next(this.resultsArray)
    };
    
    delete(o: any) {
    
      // This is the same as just accessing this.resultsArray
      let newArray: any[] = this.resultsSubject.getValue();
      for (let i = newArray.length - 1; i >= 0; i--) {
        if (newArray[i] == o) {
          newArray.splice(i, 1);
        }
      }
    
      this.resultsSubject.next(newArray);
    }
    

    解决方案2: https://stackblitz.com/edit/angular-gxfk16

    deleteSubject = new Subject<any>();
    addSubject = new Subject<any[]>();
    
    objects$ = this.myService.getObjects().pipe(
      switchMap(x => merge(
        of(x), 
        this.deleteSubject.pipe(map(y => this.deleteAll(y, x))),
        this.addSubject.pipe(map(y => { x.push(...y); return x; }))
      )),
      shareReplay(1)
    );
    constructor(private myService: MyService){ }
    
    deleteAll(o: any, v: any[]) {
      for (let i = v.length - 1; i >= 0; i--) {
        if (v[i] == o) {
          v.splice(i, 1);
        }
      }
      return v;
    }