2017-08-16 3 views
2

Ich bin mir sicher, dass dies ein einfaches Problem ist, ich weiß einfach nicht, wo ich es genau festlegen soll. Ich habe einen UserProfile-Dienst, der ein BehaviorSubject für die userdata erstellt. Wenn ich mich anmelde benutze ich diesen Dienst um die Userdata zu senden. Sobald ich eingeloggt bin, abonniere ich diese Benutzerdaten in meiner Dashbord-Komponente. Aber die beobachtbare Benutzerdatenbank gibt nur das erste leere Objekt zurück, als ich das BehaviorSubject zum ersten Mal erstellt habe. Es ist so, als würde die Login-Funktion, die die neuen Daten mit .next() versendet, nur ausgeführt, nachdem das Dashboard das BehaviourSubject abonniert hat. Ich habe versucht, die Subskription meines Dashboards in ngAfterContentInit() zu setzen, so dass die .next() vor dem Abonnement ausgeführt wird, aber ich bekomme immer noch ein leeres Objekt. Wenn ich eine .next() über die Funktion set_new_data() in meinem Dashbord ausführe, um zu überprüfen, ob das Observable funktioniert, bekomme ich die Daten von .next(); Aber ich bekomme nicht die Daten, die meine Login-Komponente über die Funktion set_userdata() in meinem Service setzt.Angular BehaviorSubject Verwendung in Service und Komponente, mögliche Race Condition

Können wir Daten mit einem Dienst nicht teilen? Wird der Dienst nach dem Verlassen der Login-Komponente zerstört oder was passiert?

Mein Userprofile Service:

@Injectable() 
export class UserProfileService { 
    public isLoggedIn: boolean = false; 
    public userdata: BehaviorSubject<any> = new BehaviorSubject<any>({}); 

    constructor() { 

    } 

    public set_userdata(data) { 
     // this.userdata = data; 
     console.log(this.userdata); 
     if (this.userdata === undefined) { 
      console.log(data); 
      //this.userdata = new BehaviorSubject<any[]>(data); 
      console.log(this.userdata); 
     } else { 
      console.log(this.userdata); 
      this.userdata.next(data); 
     } 

    } 
} 

Meine Dashbord Komponente:

@Component({ 
    selector: 'dashboard', 
    styleUrls: ['./dashboard.scss'], 
    templateUrl: './dashboard.html' 
}) 
export class Dashboard { 
    public isLoggedIn: boolean; 
    public curr_user: object; 

    constructor(private _appGlobals: AppGlobals, private _user: UserProfileService) { 
     this._appGlobals.isUserLoggedIn.subscribe(value => this.isLoggedIn = value); 
     // this.curr_user = _user.userdata; 
    } 

    ngAfterContentInit() { 
     console.log("this executes first"); 
     this._user.userdata.subscribe(value => { 
      this.curr_user = value; 
      console.log(value); 
     }); 
    } 

    set_new_data() { 
     let obj = { 
      name: "test", 
      age: 45 
     }; 
     this._user.userdata.next(obj); 
    } 
} 

Meine Konsolenausgabe, (zeigt leeres Objekt: {}, die Benutzerdaten erwartet)

enter image description here

+1

Wo stellen Sie 'UserProfileService' bereit? Warum haben Sie diese Zeile in Ihrem Code auskommentiert comment '//this.userdata = new BehaviorSubject (data);'.Es ist sicher, es vollständig zu entfernen. Es sollte nicht nötig sein, eine neue Instanz zuzuweisen. Dies würde alle Abonnements ungültig machen. –

+0

stelle ich dafür im LoginModule und im DashbordModule zur Verfügung. Diese Kommentarzeile war, weil ich versucht habe, die erste Instanz dazu zu bringen, die richtigen Daten zu haben, wenn ich das BSubject erstelle. – johan

+0

Ist eines dieser Module lazy-loaded? Um das BehaviorSubject zu initialisieren, rufen Sie einfach 'this._userdata.next (someInitialValue);' –

Antwort

1

Stellen Sie sicher, dass Sie nur eine einzige Instanz des Service haben, sonst wird der Teilnehmer auf einen anderen BehaviorSubject als Sie die Ereignisse verwenden können abonnieren Sie emittieren mit.

Das Bereitstellen eines Diensts für eine Komponente kann dazu führen, dass so viele Dienstinstanzen erstellt werden, wie Instanzen dieser Komponente erstellt werden.

Ein weiterer Fehler, der mehrere Instanzen verursachen kann, sind Lazy-Loaded-Module, die ihren eigenen DI-Root-Bereich erhalten.
Anbieter von nicht-Lazy-Loaded-Modulen werden in den Anwendungsstammbereich gehievt, und selbst wenn mehrere Module ohne Lazy-Loaded den gleichen Dienst bereitstellen, gibt es nur eine einzige Instanz.

Da DI-Bereiche nach der Initialisierung nicht aktualisiert werden können, ist es nicht möglich, Anbieter von Lazy-Loaded-Modulen in den Anwendungsstammbereich zu hissen. Daher wird ein neuer Bereich "root" erstellt (als untergeordneter Bereich des Anwendungsstamms) Gültigkeitsbereich oder ein anderer lazy-loaded "root" -Schirm) für jede Gruppe von Lazy-Loaded-Modulen, die zusammen geladen werden.

Mithilfe von forRoot können Provider aus Lazy-Loaded-Modulen zum Anwendungsstammbereich hinzugefügt werden. Siehe auch https://angular.io/guide/ngmodule-faq#what-is-the-forroot-method,
oder stellen Sie einfach den Service in AppModule oder einem anderen Modul, von dem bekannt ist, dass es nicht direkt belastet wird, zur Verfügung.

0

Wenn Sie userdata vonzurückgebenals Observable und dann abonnieren Sie diese Funktion anstelle der Subject selbst sollte Ihr Code wie erwartet funktionieren. Obwohl ich mir nicht sicher bin, was ich tun soll;

//UserProfileService 
public set_userdata(data) { //--> Maybe make this get_userdata() 
    // this.userdata = data; 
    console.log(this.userdata); 
    if (this.userdata === undefined) { 
     console.log(data); 
     console.log(this.userdata); 
    } else { 
     console.log(this.userdata); 
     this.userdata.next(data); 
    } 
    return this.userdata.asObservable(); 
} 

//Dashboard 
ngAfterContentInit() { //--> this could be in ngOnInit 
    console.log("this executes first"); 
    this._user.set_userdata().subscribe(value => { 
     this.curr_user = value; 
     console.log(value); 
    }); 
} 
+0

Danke für die Antwort, fügte ich hinzu: 'public get_userdata() { return this.userdata.asObservable(); } 'in meinem userProfile-Dienst, immer noch die set_userdata für meine Anmeldung, um die Daten zu aktualisieren. Aber immer noch leeres Objekt auf meinem Dashboard: 'this._user.get_userdata(). Subscribe (Wert => { this.curr_user = Wert; console.log (Wert); });' – johan