0

I Observable und Themen aus Rxjs bin mit zwischen zwei Komponenten zu kommunizieren, ist der Service-Teil:Wie Observable für komponentenübergreifende Kommunikation verwenden

import { 
 
    Injectable, 
 
    EventEmitter, 
 
    Output 
 
} from '@angular/core'; 
 
import { 
 
    HttpClientModule, 
 
    HttpClient 
 
} from '@angular/common/http'; 
 

 
import { 
 
    Observable 
 
} from 'rxjs/Rx'; 
 
import 'rxjs/add/operator/map'; 
 
import 'rxjs/add/operator/catch'; 
 
import { 
 
    Subject 
 
} from 'rxjs/Subject'; 
 

 

 
import { 
 
    AppConstants 
 
} from './../config/constants'; 
 

 
@Injectable() 
 

 
export class GlobalService { 
 
    private subject = new Subject <any>(); 
 
    @Output() LoggedIn: EventEmitter <any> = new EventEmitter(); 
 
    mfaData: any; 
 
    constructor(private http: HttpClient) { 
 

 
    } 
 

 
    validateCreds(postData, institutionId, customerId) { 
 
    return this.http.post(AppConstants.baseUrl + AppConstants.serverRoutes.validateCreds + institutionId + '/' + customerId, postData) 
 
     .subscribe(response => { 
 
     console.log(response); 
 
     if (response['status'] == 203) { 
 
      this.mfaData = response['body'].questions; 
 
      if (this.mfaData[0].choices || this.mfaData[0].imageChoices) { 
 
      console.log('hey there'); 
 
      this.subject.next({ 
 
       mfaData: JSON.stringify(this.mfaData) 
 
      }); 
 
      
 
      } 
 
     } 
 
     }) 
 
    } 
 

 

 
    
 

 
    refreshHeaders(): Observable <any> { 
 
    return this.subject.asObservable(); 
 
    } 
 

 

 

 

 

 
}
und ich bin mit dem Teilnehmer aus dem anruf Konstruktor einer anderen Komponente, dass der Schnipsel ist:

import { 
 
    Subscription 
 
} from 'rxjs/Subscription'; 
 
import { 
 
    GlobalService 
 
} from '../../../providers/global.serivce'; 
 

 
export class MfaChallengeComponent implements OnInit { 
 
    subscription: Subscription; 
 
    constructor(private activatedRoute: ActivatedRoute, private bankService: BanksService, private globalService: GlobalService) { 
 
    this.subscription = this.globalService.refreshHeaders().subscribe(message => { 
 
     console.log(message); 
 
    }); 
 
    } 
 
}

Aber wenn ich die Daten vom Backend erhalte, rufe ich die nächste Methode des Subjekts auf und rufe sie im Konstruktor der anderen Komponente erneut auf. Es funktioniert nicht, während ich gesehen habe, wie es funktionierte. Der Service wurde weltweit injiziert.

+0

Es gibt bereits eine wirklich gute Erklärung unten. Ich würde nur hinzufügen, dass aus der eckigen Perspektive "Konstruktor" sehr selten ein guter Ort ist, um einen Dienst aufzurufen. 'ngOnInit()' ist normalerweise, wo die Dinge stattdessen passieren sollten. –

Antwort

4

Ich fürchte, Sie missverstehen einige Kernkonzepte von RxJS. In RxJS sind die Themen heiß beobachtbar. Ein heißes Observable wird Ereignisse aussenden, egal ob jemand zuhört oder nicht. (Überprüfen Sie diesen Artikel für weitere Informationen https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html).

Nehmen wir an, Sie führen in Ihrem Dienst einen Back-End-Anruf durch, bei dem Sie das Ergebnis dieses Anrufs über das Thema "weiterleiten". Später im Code wird Ihre Komponente gestartet, und der Konstruktor wird ausgeführt und Sie beginnen, den Betreff anzuhören. Das Ereignis, das Sie durch das Thema geleitet haben, ist leider schon vorbei.

Um dies zu beheben, könnten Sie den Betreff mit einem ReplaySubject (1) ändern. Wenn ich mich nicht irre, sollte das das Problem beheben.

Es gibt jedoch einige andere Probleme mit Ihrem Code. Die Tatsache, dass Sie das Ergebnis durch ein Thema leiten, ist hier unnötig. Wenn ich mir Ihren Code ansehe, denke ich, dass Sie den Backend-Aufruf einmal durchführen und dann das Ergebnis zwischenspeichern möchten. Hierfür gibt es einen speziellen Operator namens shareReplay. Mit ihm Code würde wie folgt aussehen:

export class GlobalService { 
 
    cachedObservable$; 
 
    @Output() LoggedIn: EventEmitter <any> = new EventEmitter(); 
 
    mfaData: any; 
 
    constructor(private http: HttpClient) { 
 
    } 
 

 
    validateCreds(postData, institutionId, customerId) { 
 
    this.cachedObservable$ = this.http.post(AppConstants.baseUrl + AppConstants.serverRoutes.validateCreds + institutionId + '/' + customerId, postData) 
 
     .map(response => { 
 
     if (response['status'] == 203) { 
 
      this.mfaData = response['body'].questions; 
 
      if (this.mfaData[0].choices || this.mfaData[0].imageChoices) { 
 
      return { 
 
       mfaData: JSON.stringify(this.mfaData) 
 
      }; 
 
      } 
 
     } 
 
     }) 
 
     .shareReplay(1); 
 
    } 
 

 
    refreshHeaders(): Observable <any> { 
 
    return this.cachedObservable$; 
 
    } 
 
}

Sie erstellen einen beobachtbaren, der einmal ausgeführt wird und das Ergebnis anschließend zwischengespeichert wird. Sie sollten versuchen, Abonnements in Diensten und Betreff so weit wie möglich zu vermeiden. Um mehr über shareReplay, lesen Sie einen Blogpost über Multicasting-Betreiber in RxJS Ich schrieb: https://blog.kwintenp.com/multicasting-operators-in-rxjs

+0

Hey Ich versuchte den Code mit einigen Änderungen und es begann zu arbeiten, aber das Problem, das hier wieder auftaucht, ist, dass, wenn ich die Daten durch das Thema nächste Methode übergeben, die Subskription aufgerufen wird und es auf das Ereignis hört. Aber wenn die gleiche Komponente mit Listener-Funktion aufgerufen wird, bekomme ich die Daten nicht. – Raghav

Verwandte Themen