Tengo problemas al tratar de concatenar dos observables diferentes y mostrar los resultados en un componente de selección de material.
En este ejemplo (construido con la herramienta de Material docs) hay un ejemplo simple que simula lo que quiero hacer. No se muestran las opciones.
En mi código actual (en mi máquina), el problema que veo es: el primer Observable que se pasa al operador concat está suscrito y todos los elementos se muestran en Seleccionar. Pero creo que el primer Observable nunca se completa. Parece que material-select no está "completando" el primer Observable y, por eso, concat no se suscribirá al próximo Observable mientras que el primero nunca se completa, como dice en sus documentos :
Tenga en cuenta que si algún Observable de entrada nunca se completa, concat tampoco se completará nunca y los Observables que siguen al que no se completó nunca se suscribirán.
Lo que necesito es esto: tomar dos Observables diferentes (con datos diferentes en cada uno), concatenarlos (o cualquier otra operación) y, al final, mostrar todos sus datos combinados como opciones de un solo componente de selección.
Solo como referencia, copiaré el código aquí también, para que no se pierda en el futuro:
// Component: import { Component, Input } from '@angular/core'; import { from } from 'rxjs'; import { concatWith } from 'rxjs/operators'; interface Option { value: number; label: string; } @Component({ selector: 'select-overview-example', templateUrl: 'select-overview-example.html', }) export class SelectOverviewExample { @Input() options$: any; constructor() {} ngOnInit() { // Let's pretend this data comes from API 1 const sourceA$ = from([ { value: 1, label: 'Value 1' }, { value: 2, label: 'Value 2' }, { value: 3, label: 'Value 3' }, ]); // And these ones comes from API 2 const sourceB$ = from([ { value: 4, label: 'Value 4' }, { value: 5, label: 'Value 5' }, { value: 6, label: 'Value 6' }, ]); // Now, concat the data from both observables and display all of them as options in a Select component: this.options$ = concatWith(sourceA$, sourceB$); } }Y la plantilla:
<h4>Basic mat-select</h4> <mat-form-field appearance="fill"> <mat-label>Select some value:</mat-label> <mat-select> <mat-option *ngFor="let option of (options$ | async)" [value]="option.value" > {{option.label}} </mat-option> </mat-select> </mat-form-field>Puede recopilar los valores de múltiples observables utilizando la función de combinación y el operador de escaneo de la siguiente manera:
import { from, merge } from 'rxjs'; import { scan } from 'rxjs/operators'; const sourceA$ = from(/* ... */); const sourceB$ = from(/* ... */); merge(sourceA$, sourceB$) .pipe( scan((acc, value) => { acc.push(value); return acc; }, []) ) .subscribe((value) => console.log(value)); En este ejemplo, puede reemplazar merge con concat y aún funciona. Si el orden es importante y desea obtener todos los valores de sourceA$ antes de suscribirse a sourceB$ , entonces tiene razón en que debe usarse concat en lugar de merge .
Con respecto a tu comentario...
Parece que material-select no está "completando" el primer Observable
No es responsabilidad de material-select completar la fuente Observable. Es responsabilidad de la fuente Observable completar. material-select no tiene forma de saber cuándo la fuente Observable termina de emitir valores sin que la fuente Observable se complete a sí misma.
Usar forkJoin y luego fusionar las dos matrices debería ser una opción buena y limpia:
this.options$ = forkJoin([sourceA$, sourceB$]).pipe( // runs both parallel map(res => { const sA = res[0]; const sB = res[1]; return [...sA, ...sB]; // merges two array using the spread operator }) );