简体   繁体   English

Angular 8 rxjs从多个可观察对象获取值

[英]Angular 8 rxjs get values from multiple observables

I am using rxjs switchMap to get the latest form value from a subject, set a local variable and then perform a query based on that value. 我正在使用rxjs switchMap从主题获取最新的表单值,设置局部变量,然后基于该值执行查询。

Long story short I am populating select box options based on the current value of the form. 长话短说,我正在基于表单的当前值填充选择框选项。

  // Get current value of Record Form
  this.recordFormService.recordForm$
    .pipe(
      switchMap(recordForm => {
        // Get current Product Owner on Record Form
        this.currentProductOwner = recordForm.value.ProductOwner;

        // Search People
        return this.recordsApiService.searchPeople$(this.currentProductOwner);
      }),
      catchError(err => {
        console.error(`get recordForm$ failed ${err}`);
        return throwError(err);
      })
    )
    .subscribe(results => {
      // Set Product Owners select box options
      this.productOwners = results.data;
    });

This is all working properly. 这一切都正常工作。

However, I also need to perform the same exact logic when a specific form value changes. 但是,当特定表单值更改时,我还需要执行相同的确切逻辑。

// Run the same logic when the ProductOwner value changes
this.parentFormGroup.controls['ProductOwner'].valueChanges.subscribe(val => {});

I tried putting the combineLatest operator at the top, however that only resolves when both observables have emitted at least one value. 我尝试将combineLatest运算符放在顶部,但是只有两个可观察对象都发出了至少一个值时才能解决。

The valueChanges observable may not necessarily ever change, but recordFormService.recordForm$ will run at least once when the page is loaded. 可以观察到的valueChanges不一定会更改,但是recordFormService.recordForm $将在加载页面时至少运行一次。

Note: The result of the valueChanges observable is a string and the result of the recordForm$ observable is a FormGroup object, they need to be processed entirely differently. 注意: valueChanges observable的结果是一个字符串,而recordForm$ observable的结果是一个FormGroup对象,需要完全不同地对其进行处理。

What operator can I use to achieve this requirement? 我可以使用什么运营商来达到此要求?

// Get latest value of all observables
combineLatest(
  this.parentFormGroup.controls['ProductOwner'].valueChanges,
  // Get current value of Record Form
  this.recordFormService.recordForm$
)
.pipe(
  switchMap(recordForm => {
    // Get current Product Owner on Record Form
    this.currentProductOwner = recordForm.value.ProductOwner;

    // Search People
    return this.recordsApiService.searchPeople$(this.currentProductOwner);
  }),
  catchError(err => {
    console.error(`get recordForm$ failed ${err}`);
    return throwError(err);
  })
)
.subscribe(results => {
  // Set Product Owners select box options
  this.productOwners = results.data;
});

UPDATE: 更新:

I also tried merge . 我也尝试过merge However the results of both observables are entirely different (one is a formGroup and one is a string) and they both need to be processed differently. 但是,两个可观察值的结果完全不同(一个是formGroup,一个是字符串),并且都需要以不同的方式进行处理。

// Get latest value of all observables
merge(
  this.parentFormGroup.controls['ProductOwner'].valueChanges,
  // Get current value of Record Form
  this.recordFormService.recordForm$
)

You'll want merge : 您需要合并

import { merge } from 'rxjs';

Make 2 observables that emit the same type from the observables you want to react to. 使2个可观测对象发出与您要反应的可观测对象相同类型的可观测对象。 I am using a fake type RecordForm which holds your form value and the product owner as an example: 我使用的是一个伪造的RecordForm类型,它保存您的表单值和产品所有者作为示例:

const ownerChanges$: Observable<RecordForm> = this.parentFormGroup.controls['ProductOwner'].valueChanges.pipe(
  withLatestFrom(this.recordFormService.recordForm$),
  map(([owner, recordForm]) => ({ ...recordForm, owner }))
);
const formChanges$: Observable<RecordForm> = this.recordFormService.recordForm$.pipe(
  withLatestFrom(this.parentFormGroup.controls['ProductOwner'].valueChanges),
  map(([recordForm, owner]) => ({ ...recordForm, owner }))
);

Then pass them to merge: 然后将它们传递给合并:

// Get latest value of all observables
merge(ownerChanges$, recordChanges$).pipe(
  ...
  // the type passed here is always RecordForm - react accordingly
)
.subscribe(results => {
  // Set Product Owners select box options
  this.productOwners = results.data;
});

But you'll want to make sure both observables passed to merge are the same type, so they can be handled the same way. 但是,您需要确保传递给merge两个可观察对象具有相同的类型,以便可以以相同的方式处理它们。

I think what you want to do is create another downstream observable; 我认为您想要做的是创建另一个下游可观察到的东西。 the one for your form input that should trigger the API call as well as the original observable. 您的表单输入应触发API调用以及原始的可观察者。 To do this you can use mergeMap pipe on the original Observable. 为此,您可以在原始Observable上使用mergeMap管道。 This will create another Emitter inside that can emit in parallel from the first. 这将在内部创建另一个发射器,该发射器可以从第一个发射器并行发射。 Try this: 尝试这个:

const formObs$ = this.parentFormGroup.controls['ProductOwner'].valueChanges;

this.recordFormService.recordForm$.pipe(
  // give precedence in the merge callback to the original stream Observable,
  // but if just the second Observable fires here, grab that value and use it to pass downstream
  mergeMap(() => formObs$, (originalValue, formObsValue) => originalValue || formObsValue),
  // now recordForm is either from the original observable, or from your form input
  switchMap(recordForm => {
    this.currentProductOwner = recordForm.value.ProductOwner;

    // Search People
    return this.recordsApiService.searchPeople$(this.currentProductOwner);
  }),
  catchError(err => {
    console.error(`get recordForm$ failed ${err}`);
    return throwError(err);
  })
).subscribe(results => {
  // Set Product Owners select box options
  this.productOwners = results.data;
});

I'm making the assumption here that recordForm$ is returning a form value just like your second observable .valueChanges . 我在这里假设recordForm $返回一个表单值,就像您的第二个observable .valueChanges If that's not the case, you'll just need to massage it in the mergeMap 2nd callback function to produce a merged value to the switchMap that you want. 如果不是这种情况,您只需要在mergeMap 2nd回调函数中对其进行按摩,以生成所需的switchMap的合并值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM