Hamburgers N'Heroin Hamburgers N'Heroin - 8 days ago 4
AngularJS Question

ANGULAR 2 - Component Shared Data Service

this has really been wreaking my head.

I have a nice little app with social login setup using Firebase and Angular 2.

Everything should be realtime. Basically when a user logs in via Facebook I want their personal info to be passed to a service and stored as an Observable and display instantly in any component that subscribes to the service, I then want to be able to access this Observable from within Components that are not directly linked to each other and may even be totally out of the hierarchy.. hence why I cant use @Input or an EventEmitter etc..

I have tried a lot of different things but at its most stripped back this is what i currently have, a login component that passes the users data to the service and then a random component that should be able to access this data in realtime as soon as it hits the service.

* my login component *

import { Component, OnInit } from '@angular/core';
import { AngularFire, AuthProviders, AuthMethods, FirebaseListObservable } from 'angularfire2';
import { Router } from '@angular/router';
import { GlobaluserService } from '../globaluser.service';
import { Subject } from 'rxjs/Subject';


@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {

email: string;
password: string;
userData = {};
_api;

constructor( public af: AngularFire, private router: Router, private api: GlobaluserService ) {
this._api = this.api;
}

loginFacebook() {
this.af.auth.login({
provider: AuthProviders.Facebook,
method: AuthMethods.Popup,
}).then( ( facebookUser ) => {

this.userData = {
uID: facebookUser.auth.uid,
profilePic: facebookUser.auth.photoURL,
username: facebookUser.auth.displayName,
email: facebookUser.auth.email,
platform: 'facebook'
}

this._socialLoginProcess( this.userData ); // this method is described below

}).catch( (error) => {
console.log("Facebook failure: " + JSON.stringify(error));
});
}

// passes the user data to the shared service and outputs the data in the console
_socialLoginProcess( userData ) {
this._api.saveData(userData);
console.log("Login Success: " + JSON.stringify( this.userData ));
}


}


* Shared Service *

import { Component, Injectable,Input,Output,EventEmitter } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/map';


// Name Service
export interface usersData {
uID: string,
profilePic: string,
username: string,
email: string,
platform: string
}


@Injectable()
export class GlobaluserService {

sharingData: Observable<usersData[]>

private _sharingData: BehaviorSubject<usersData[]>;

private dataStore: {
sharingData: usersData[]
};


constructor() {
this.dataStore = { sharingData: [] };
this._sharingData = <BehaviorSubject<usersData[]>>new BehaviorSubject([]);
}

saveData( userData ) {
this.sharingData = userData;
}

getData() {
console.log('get data function called' + JSON.stringify( this.sharingData ) );
return this._sharingData.asObservable();
}


}


* Random Component I wish to be able to get the users data from this service *

import { Component, OnInit, Input } from '@angular/core';
import { AngularFire, AuthProviders, FirebaseListObservable } from 'angularfire2';
import { Router } from '@angular/router';
import { GlobaluserService } from '../globaluser.service';

@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})

export class NavigationComponent implements OnInit {

isAuth = false;
user = {};

subscription : any;
userKonte : any;
_userAPIservice: any;

constructor( private router: Router, private api: GlobaluserService ) {

this.subscription = this.api.getData().subscribe( _sharingData => {
this.userKonte = _sharingData;
console.log( JSON.stringify( this.userKonte ) );
});

}

ngOnInit(){
console.log( JSON.stringify( this.userKonte ) );
}





}

Answer

Instead of

saveData( userData ) {
  this.sharingData = userData; 
}

when you want to emit a new value, you need to next on the BehaviorSubject

saveData( userData ) {
  this._sharingData.next(userData); 
}

Because getData is getting the observable from the subject, the subscribers to the observable will get the new emissions on the subject when next is called