I'm creating a service for my MongoDB Stitch connections and I'm having an issue where if I refresh my page I get an error saying:
client for app 'xyxyxyxyxyxy' has not yet been initialized
And when I try to initialize it I get an error saying it has already been initialized.
client for app 'xyxyxyxyxyxy' has already been initialized
Here is my service.
import { Injectable } from '#angular/core';
import { Stitch, RemoteMongoClient, UserApiKeyCredential} from 'mongodb-stitch-browser-sdk';
#Injectable({
providedIn: 'root'
})
export class AnalyticsService {
client: any;
credential: UserApiKeyCredential;
db: any;
constructor() {
console.log(Stitch.hasAppClient('xyxyxyxyxyxy'));
if (!Stitch.hasAppClient('xyxyxyxyxyxy')) {
this.client = Stitch.initializeDefaultAppClient('xyxyxyxyxyxy');
} else {
console.log('here');
this.client = Stitch.initializeAppClient('xyxyxyxyxyxy');
//this.client = Stitch.getAppClient('xyxyxyxyxyxy');
}
this.db = this.client.getServiceClient(RemoteMongoClient.factory, 'mongodb-atlas').db('DBNAME');
}
login() {
this.credential = new UserApiKeyCredential('APIKEY');
this.client.auth.loginWithCredential(this.credential)
.then(authId => {
console.log(authId);
});
}
logout() {
this.client.auth.logout()
.then(resp => {
console.log(resp);
});
}
insertData(collectionName: string, data: {}) {
this.db.collection(collectionName).insertOne(data)
.then(resp => {
console.log(resp);
});
}
getData(collectionName: string) {
this.db.collection(collectionName).find({})
.asArray().then(resp => {
console.log(resp);
});
}
}
Change the constructor to be like this and it fix the issue.
constructor() {
if (!Stitch.hasAppClient('xyxyxyxyxyxy')) {
this.client = Stitch.initializeDefaultAppClient('xyxyxyxyxyxy');
} else {
this.client = Stitch.defaultAppClient;
}
this.db = this.client.getServiceClient(RemoteMongoClient.factory, 'mongodb-atlas').db('DBNAME');
}
Related
i am consuming Rest JSONP Web Service in an ionic App which works fine on PC but returns null value on mobile devices
My page.ts file
import {
Component,
OnInit
} from '#angular/core';
import {
AlertController,
LoadingController
} from '#ionic/angular';
import {
ActionSheetController
} from '#ionic/angular';
import {
Router
} from '#angular/router'
import {
ProApiService
} from './../../../../services/pro-api.service';
#Component({
selector: 'app-ranked-diagnosis',
templateUrl: './ranked-diagnosis.page.html',
styleUrls: ['./ranked-diagnosis.page.scss'],
})
export class RankedDiagnosisPage implements OnInit {
tabSelect: string = 'show10';
show10Data: Array < any >= [];
showAllData: Array < any >= [];
redFlagsData: Array < any >= [];
loading: any;
constructor(
private api: ProApiService,
public alertController: AlertController,
public loadingController: LoadingController,
public actionSheetController: ActionSheetController,
private router: Router
) {}
segmentChanged(event: any) {
this.tabSelect = event.detail.value;
}
async presentActionSheet(buttons) {
const actionSheet = await this.actionSheetController.create({
header: 'Sub Diagnosis',
buttons: buttons
});
await actionSheet.present();
}
async presentAlert(msg: string, header: string) {
const alert = await this.alertController.create({
header: '',
subHeader: header,
message: msg,
buttons: ['OK']
});
await alert.present();
}
async presentLoading() {
this.loading = await this.loadingController.create({
message: 'loading...',
});
return await this.loading.present();
}
ngOnInit() {
}
ionViewWillEnter() {
if (this.api.ProApiData.diagnoses_checklist.diagnoses) {
this.showAllData =
this.api.ProApiData.diagnoses_checklist.diagnoses;
for (let i = 0; i < 10; i++) {
this.show10Data.push(this.showAllData[i]);
}
this.showAllData.forEach(item => {
if (item.red_flag == 'true') {
this.redFlagsData.push(item);
}
});
console.log(this.showAllData);
} else {
console.log('error');
this.router.navigateByUrl('isabel-pro');
}
}
why_diagnosis(url: any, weightage: any) {
this.presentLoading();
this.api.why_diagnosisApi(url).subscribe(res => {
let matched_terms = res._body.why_diagnosis.matched_terms;
console.log(matched_terms);
let alertMsg = `We matched the terms: ${matched_terms}<br><hr>Degree of match between query entered and database: ${weightage}`;
this.presentAlert(alertMsg, 'Why did this diagnosis come up ?');
this.loadingController.dismiss();
}, err => {
this.loadingController.dismiss();
console.log('error');
});
}
}
in the above code i am calling why_diagnosis function which calls the function from a service file.
My service.ts file
import {
Injectable
} from '#angular/core';
import {
HttpClient,
HttpHeaders
} from '#angular/common/http';
import {
Jsonp
} from '#angular/http';
import {
Observable
} from 'rxjs';
import {
map
} from 'rxjs/operators';
import {
ConstantsService
} from './../../../services/constants.service';
#Injectable({
providedIn: 'root'
})
export class ProApiService {
apiRoot = this.root.APIroot;
diagnosisPROData: any;
drugData: any;
ProApiData: any;
drugApiData: any;
constructor(
private jsonp: Jsonp,
private http: HttpClient,
private root: ConstantsService) {}
why_diagnosisApi(url: any): Observable < any > {
let whyUrl = `${this.apiRoot}Mob_isabelPRO.php?
why_url=${url}&callback=JSONP_CALLBACK`;
return this.jsonp.request(whyUrl, 'callback')
.pipe(
map(
res => {
let why_diagnosis = res;
return why_diagnosis;
}
)
);
}
}
above code is from my service file.
this is the value i am getting in PC
this is the return on mobile
i dont know whats wrong with it. please suggest me the solution
Thanks
I am trying to use #waves/waves-crypto I have import * as wavesCrypto from '#waves/waves-crypto' in my .ts file but I am still getting error within the npm module itself. I am trying to create a waves wallet using nativescript and right now I am trying to create the address and seed and public and private key for the user. this is login.ts where im calling the #waves/waves-crypto
import { Component, ElementRef, ViewChild } from "#angular/core";
import { Router } from "#angular/router";
import { alert, prompt } from "tns-core-modules/ui/dialogs";
import { Page } from "tns-core-modules/ui/page";
import { Routes } from "#angular/router";
//import { publicKey, verifySignature, signBytes, address, keyPair, privateKey } from "../#waves/waves-crypto";
import * as wavesCrypto from '../#waves/waves-crypto';
import { User } from "../shared/user.model";
import { UserService } from "../shared/user.service";
#Component({
selector: "app-login",
moduleId: module.id,
templateUrl: "./login.component.html",
styleUrls: ['./login.component.css']
})
export class LoginComponent {
isLoggingIn = true;
user: User;
#ViewChild("password") password: ElementRef;
#ViewChild("confirmPassword") confirmPassword: ElementRef;
#ViewChild("waves") waves: ElementRef;
constructor(private page: Page, private userService: UserService, private router: Router) {
this.page.actionBarHidden = true;
this.user = new User();
// this.user.email = "foo2#foo.com";
// this.user.password = "foo";
const seed = 'magicseed';
const pubKey = wavesCrypto.publicKey(seed);
const bytes = Uint8Array.from([1, 2, 3, 4]);
const sig = wavesCrypto.signBytes(bytes, seed);
const isValid = wavesCrypto.verifySignature(pubKey, bytes, sig)
}
wallet() {
let walletAddress = wavesCrypto.address('seed', 'T');
let keyPair = wavesCrypto.keyPair('seed');
//publicKey('seed');
//privateKey('seed');
wavesCrypto.privateKey('seed');
alert(walletAddress);
console.log(walletAddress);
console.log(keyPair);
}
toggleForm() {
this.isLoggingIn = !this.isLoggingIn;
}
submit() {
if (!this.user.email || !this.user.password) {
this.alert("Please provide both an email address and password.");
return;
}
if (this.isLoggingIn) {
this.login();
} else {
this.register();
}
}
login() {
this.userService.login(this.user)
.then(() => {
this.router.navigate(["/home"]);
})
.catch(() => {
this.alert("Unfortunately we could not find your account.");
});
}
register() {
if (this.user.password != this.user.confirmPassword) {
this.alert("Your passwords do not match.");
return;
}
this.userService.register(this.user)
.then(() => {
this.alert("Your account was successfully created.");
this.isLoggingIn = true;
})
.catch(() => {
this.alert("Unfortunately we were unable to create your account.");
});
}
forgotPassword() {
prompt({
title: "Forgot Password",
message: "Enter the email address you used to register for APP NAME to reset your password.",
inputType: "email",
defaultText: "",
okButtonText: "Ok",
cancelButtonText: "Cancel"
}).then((data) => {
if (data.result) {
this.userService.resetPassword(data.text.trim())
.then(() => {
this.alert("Your password was successfully reset. Please check your email for instructions on choosing a new password.");
}).catch(() => {
this.alert("Unfortunately, an error occurred resetting your password.");
});
}
});
}
focusPassword() {
this.password.nativeElement.focus();
}
focusConfirmPassword() {
if (!this.isLoggingIn) {
this.confirmPassword.nativeElement.focus();
}
}
alert(message: string) {
return alert({
title: "APP NAME",
okButtonText: "OK",
message: message
});
}
}
I have the same problem and I opened the next issue on the Github repo (you can go and click like or comment), link here
In the issue I explain a workaround that is working for me to validate a signature, you can use the same snippet.
First import manually the submodules needed:
import { default as axlsign } from '#waves/signature-generator/libs/axlsign';
import { default as convert } from '#waves/signature-generator/dist/utils/convert';
import { concatUint8Arrays } from '#waves/signature-generator/dist/utils/concat';
import { default as base58 } from '#waves/signature-generator/dist/libs/base58';
Then you can use the next code to validate the signature and publickey:
let prefix = "WavesWalletAuthentication";
let host = new URL(yourServerUrl).hostname;
let user = wavesAddressString;
let payload = theStringThatWasSigned;
let data = [prefix, host, payload]
.map(d => convert.stringToByteArrayWithSize(d))
.map(stringWithSize => Uint8Array.from(stringWithSize));
let dataBytes = concatUint8Arrays(...data);
let publicKeyBytes = base58.decode(publicKeyOnBase58Format);
let signatureBytes = base58.decode(signatureOnBase58Format);
let validSignature = axlsign.verify(publicKeyBytes, dataBytes, signatureBytes);
console.log("(login) validSignature?", validSignature);
I have an interesting problem with IONIC-3 that I've not been able to solve. I am attempting to implement an auth routing which is triggered by ionViewCanEnter. However, while I can pass one nav setter, it will not allow multiple. Here is the code:
AuthService Function:
isAuthenticated(nav: NavController): boolean | Promise<any> {
const userAuth = this.uData.getAuthenticated;
const userProfile = this.uData.getUserProfile;
if (userAuth ) {
//User is logged in, so let's check a few things.
if (!userProfile.sign_up_complete) {
//User has not completed sign up
setTimeout(() => { nav.setRoot(CreateAccountPage) }, 0);
}
return true
} else {
//User is not authenticated, return to walkthrough
setTimeout(() => { nav.setRoot(WalkthroughPage) }, 0);
return false
}}
Example calling:
ionViewCanEnter(): boolean | Promise<any> {
return this.auth.isAuthenticated(this.nav);
}
If I have only CreateAccountPage, the script runs fine. However, when I add WalkthroughPage, it throws the following error:
Error: Can't resolve all parameters for ListingPage: (?, [object Object], [object Object], [object Object]).
Which is an error related to the AuthService. For clarity the WalkthroughPage code is as follows:
import { Component, ViewChild } from '#angular/core';
import { IonicPage, NavController, Slides } from 'ionic-angular';
import { RemoteConfigProvider } from '../../providers/remote-config/remote-config';
import { LoginPage } from '../login/login';
import { SignupPage } from '../signup/signup';
#IonicPage()
#Component({
selector: 'walkthrough-page',
templateUrl: 'walkthrough.html'
})
export class WalkthroughPage {
lastSlide = false;
sign_up_enabled: null;
sign_in_enabled: null;
#ViewChild('slider') slider: Slides;
constructor(public nav: NavController,
public remoteConfig: RemoteConfigProvider) {
}
ionViewDidLoad() {
this.remoteConfig.getValue('sign_up_enabled').then(t => {
this.sign_up_enabled = t;
})
this.remoteConfig.getValue('sign_in_enabled').then(t => {
this.sign_in_enabled = t;
})
}
skipIntro() {
this.lastSlide = true;
this.slider.slideTo(this.slider.length());
}
onSlideChanged() {
this.lastSlide = this.slider.isEnd();
}
goToLogin() {
this.nav.push(LoginPage);
}
goToSignup() {
this.nav.push(SignupPage);
}
}
I have attempted to compare both pages, but not identified the exact cause. I welcome any thoughts.
For those who encounter a similar issue, the fix was straight forward. I simply used deep-linking reference which resolved all issues. Example below.
isAuthenticated(nav: NavController): boolean | Promise<any> {
const userAuth = this.userStore.getAuthenticated;
const userProfile = this.userStore.getUserProfile;
if (userAuth) {
return true
} else {
console.log('Auth guard: Not authenticated');
setTimeout(() => { nav.setRoot('no-access') }, 0);
return false
}
}
I am trying to implement a catch for 401 responses and tried obtaining a refresh token based on Angular 4 Interceptor retry requests after token refresh. I was trying to implement the same thing, but I never was able to Retry that request, and I am really not sure if that is the best approach to apply the refresh token strategy.
Here is my code:
#Injectable()
export class AuthInterceptorService implements HttpInterceptor {
public authService;
refreshTokenInProgress = false;
tokenRefreshedSource = new Subject();
tokenRefreshed$ = this.tokenRefreshedSource.asObservable();
constructor(private router: Router, private injector: Injector) { }
authenticateRequest(req: HttpRequest<any>) {
const token = this.authService.getToken();
if (token != null) {
return req.clone({
headers: req.headers.set('Authorization', `Bearer ${token.access_token}`)
});
}
else {
return null;
}
}
refreshToken() {
if (this.refreshTokenInProgress) {
return new Observable(observer => {
this.tokenRefreshed$.subscribe(() => {
observer.next();
observer.complete();
});
});
} else {
this.refreshTokenInProgress = true;
return this.authService.refreshToken()
.do(() => {
this.refreshTokenInProgress = false;
this.tokenRefreshedSource.next();
}).catch(
(error) => {
console.log(error);
}
);
}
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.authService = this.injector.get(AuthenticationService);
request = this.authenticateRequest(request);
return next.handle(request).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
return this.refreshToken()
.switchMap(() => {
request = this.authenticateRequest(request);
console.log('*Repeating httpRequest*', request);
return next.handle(request);
})
.catch(() => {
return Observable.empty();
});
}
}
});
}
}
The issue is that SwitchMap is never reached in...
if (err.status === 401) {
return this.refreshToken()
.switchMap(() => {
and the do operator as well...
return this.authService.refreshToken()
.do(() => {
so that took me to my authService refreshToken method...
refreshToken() {
let refreshToken = this.getToken();
refreshToken.grant_type = 'refresh_token';
refreshToken.clientId = environment.appSettings.clientId;
return this.apiHelper.httpPost(url, refreshToken, null)
.map
(
response => {
this.setToken(response.data, refreshToken.email);
return this.getToken();
}
).catch(error => {
return Observable.throw('Please insert credentials');
});
}
}
It returns a mapped observable, and I know it needs a subscription if I replaced the do in...
return this.authService.refreshToken()
.do(() => {
With subscribe I'll break the observable chain I guess. I am lost and I've playing with this for a long time without a solution. :D
I'm glad that you like my solution. I'm going to put just the final solution here but if anybody wants to know the process that I fallowed go here: Refresh Token OAuth Authentication Angular 4+
Ok, First I created a Service to save the state of the refresh token request and Observable to know when the request is done.
This is my Service:
#Injectable()
export class RefreshTokenService {
public processing: boolean = false;
public storage: Subject<any> = new Subject<any>();
public publish(value: any) {
this.storage.next(value);
}
}
I noticed that It was better if I have two Interceptors one to refresh the token and handle that and one to put the Authorization Header if exist.
This the Interceptor for Refresh the Token:
#Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector, private tokenService: RefreshTokenService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
if (!auth.hasAuthorization() && auth.hasAuthorizationRefresh() && !this.tokenService.processing && request.url !== AUTHORIZE_URL) {
this.tokenService.processing = true;
return auth.refreshToken().flatMap(
(res: any) => {
auth.saveTokens(res);
this.tokenService.publish(res);
this.tokenService.processing = false;
return next.handle(request);
}
).catch(() => {
this.tokenService.publish({});
this.tokenService.processing = false;
return next.handle(request);
});
} else if (request.url === AUTHORIZE_URL) {
return next.handle(request);
}
if (this.tokenService.processing) {
return this.tokenService.storage.flatMap(
() => {
return next.handle(request);
}
);
} else {
return next.handle(request);
}
}
}
So here I'm waiting to the refresh token to be available or fails and then I release the request that needs the Authorization Header.
This is the Interceptor to put the Authorization Header:
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(OAuthService);
let req = request;
if (auth.hasAuthorization()) {
req = request.clone({
headers: request.headers.set('Authorization', auth.getHeaderAuthorization())
});
}
return next.handle(req).do(
() => {},
(error: any) => {
if (error instanceof HttpErrorResponse) {
if (error.status === 401) {
auth.logOut();
}
}
});
}
}
And my main module is something like this:
#NgModule({
imports: [
...,
HttpClientModule
],
declarations: [
...
],
providers: [
...
OAuthService,
AuthService,
RefreshTokenService,
{
provide: HTTP_INTERCEPTORS,
useClass: RefreshTokenInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Please any feedback will be welcome and if I'm doning something wrong tell me. I'm testing with Angular 4.4.6 but I don't know if it work on angular 5, I think should work.
Below interceptors do this task for you
import {
throwError as observableThrowError,
Observable,
Subject,
EMPTY,
} from 'rxjs';
import { catchError, switchMap, tap, finalize } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpSentEvent,
HttpHeaderResponse,
HttpProgressEvent,
HttpResponse,
HttpUserEvent,
HttpErrorResponse,
} from '#angular/common/http';
import { StoreService } from './store.service';
import { ApiService } from './api.service';
export const tokenURL = '/315cfb2a-3fdf-48c3-921f-1d5209cb7861'; //copied from api service
#Injectable()
export class SessionInterceptorService implements HttpInterceptor {
isRefreshingToken: boolean = false;
cachedRequests = [];
tokenSubject: Subject<string> = new Subject<string>();
constructor(
private readonly store: StoreService,
private readonly ApiService: ApiService
) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<
| HttpSentEvent
| HttpHeaderResponse
| HttpProgressEvent
| HttpResponse<any>
| HttpUserEvent<any>
> {
let urlPresentIndex = this.cachedRequests.findIndex(
(httpRequest) => httpRequest.url == req.url
);
if (this.isRefreshingToken && !req.url.endsWith(tokenURL)) {
// check if unique url to be added in cachedRequest
if (urlPresentIndex == -1) {
this.cachedRequests.push(req);
return this.tokenSubject.pipe(
switchMap(() => next.handle(req)),
tap((v) => {
// delete request from catchedRequest if api gets called
this.cachedRequests.splice(
this.cachedRequests.findIndex(
(httpRequest) => httpRequest.url == req.url
),
1
);
return EMPTY;
})
);
} else {
//already in cached request array
return EMPTY;
}
}
return next.handle(this.updateHeader(req)).pipe(
catchError((error) => {
console.log(error);
if (error instanceof HttpErrorResponse) {
switch ((<HttpErrorResponse>error).status) {
case 400:
return this.handle400Error(error);
case 403 || 401:
if (req.url.endsWith(tokenURL)) {
return observableThrowError(error);
} else {
this.cachedRequests.push(req);
return this.handle401Error(req, next);
}
default:
return observableThrowError(error);
}
} else {
return observableThrowError(error);
}
})
);
}
handle400Error(error) {
if (
error &&
error.status === 400 &&
error.error &&
error.error.error === 'invalid_grant'
) {
// If we get a 400 and the error message is 'invalid_grant', the token is no longer valid so logout.
return this.logout();
}
return observableThrowError(error);
}
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
return this.ApiService.refreshToken().pipe(
switchMap((newToken: string) => {
if (newToken) {
this.store.updateAccessToken(newToken);
this.tokenSubject.next(newToken);
return next.handle(this.updateHeader(this.cachedRequests[0]));
}
// If we don't get a new token, we are in trouble so logout.
return this.logout();
}),
catchError((error) => {
// If there is an exception calling 'refreshToken', bad news so logout.
return this.logout();
}),
finalize(() => {
this.isRefreshingToken = false;
})
);
}
}
logout() {
console.log('logging it out');
// Route to the login page (implementation up to you)
return observableThrowError('');
}
/*
This method is append token in HTTP request'.
*/
updateHeader(req) {
const authToken = this.store.getAccessToken();
console.log(authToken);
req = req.clone({
headers: req.headers.set('X-RapidAPI-Key', `${authToken}`),
});
return req;
}
}
For more details you can read my medium article Token-Refresh-Interceptor-retry-failed-Requests
Check it out, how it works stackblitz
I'm building an observable data service based on the following article: https://coryrylan.com/blog/angular-2-observable-data-services
In the article he used an array as an example, here I will use the user object since I'm developing the user service.
Here's what I got:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Events, SqlStorage, Storage } from 'ionic-angular';
import { Subject } from 'rxjs/Subject';
export interface DataStore {
user: Object
}
#Injectable()
export class UserService {
private baseUrl: string;
private storage: Storage;
private _user$: Subject<Object>;
private dataStore: DataStore;
constructor(
private http: Http
) {
this.baseUrl = 'http://localhost:3000';
this.storage = new Storage(SqlStorage);
this._user$ = <Subject<Object>>new Subject();
this.dataStore = {
user: { name: '' }
};
}
set user$(user: Object) {
this.storage.set('user', JSON.stringify(user));
this.dataStore.user = user;
this._user$.next(this.dataStore.user);
}
get user$() {
return this._user$.asObservable();
}
loadUser() {
return this.storage.get('user').then(
((user: string): Object => {
this.dataStore.user = JSON.parse(user);
this._user$.next(this.dataStore.user);
return this.dataStore.user;
})
);
}
login(accessToken: string) {
return this.http
.post('http://localhost:3000/login', { access_token: accessToken })
.retry(2)
.map((res: Response): any => res.json());
}
logout(): void {
this.storage.remove('user');
}
}
To authenticate I call the login() function and set the user data if everything ok.
this.userService.login(this.data.accessToken)
.subscribe(
(user: Object) => {
this.userService.user$ = user;
this.nav.setRoot(EventListComponent);
},
(error: Object) => console.log(error)
);
I feel it is better set the user data inside the service. I could do the following:
login(accessToken: string) {
return this.http
.post('http://localhost:3000/login', {
access_token: accessToken
})
.retry(2)
.map((res: Response): any => res.json())
.subscribe(
(user: Object) => {
this.userService.user$ = user;
this.nav.setRoot(EventListComponent);
},
(error: Object) => console.log(error)
);
}
But I won't be able to subscribe to the login() function in the component since it's already subscribed. How could I redirect the user if everything ok or show an alert if anything goes wrong in the component but setting the user inside the service?
In the main component I load the user data and set the rootPage:
this.userService.loadUser().then(
(user: Object) => this.rootPage = EventListComponent,
(error: Object) => this.rootPage = LoginComponent
);
I thought that calling the loadUser() function at this time I would not have to call it again, but I have to call it in all components that I need the user data:
this.user = this.userService.user$;
this.userService.loadUser();
I don't think the service is the way it should, what could I improve? Is there any better way to achieve what I want? Any example or idea?