0

I am very confused as to why the variables is not holding.
I have a variable user which is assigned with the data in userData(). But it's undefined when console log within the constructor and ProfilePage.

enter image description here

share-service.ts

export class ShareService {
  uid: string;
  user;

  constructor(public db: AngularFireDatabase) {
    let currentUser = firebase.auth().currentUser;
    this.uid = currentUser.uid;
    this.userData();
    console.log('[constructor]user: ', this.user);
  }

  userData() {
    this.db.object(`users/${this.uid}`).snapshotChanges().subscribe(data => {
      this.user = data.payload.val();
      console.log('[userData]user: ', this.user);
    });
  }

  getUser() {
    return this.user;
  }

}

profile.ts

export class ProfilePage {
  user;

  constructor(public navCtrl: NavController, public firebaseService: FirebaseService, shareService: ShareService) {
    console.log('[profile.ts]', shareService.getUser());
  }

}
  • "angularfire2": "5.0.0-rc.4",
  • "firebase": "4.8.2",
  • "ionic-angular": "3.9.2",
  • "rxjs": "^5.5.6",
  • "@ionic/app-scripts": "3.1.8",
  • "typescript": "2.4.2"

I have already tried searching for similar questions like for example this and read that it has something to do with how angular is asynchronous and then upon further investigation I read that promise is needed like this. I also read somewhere that .then() should be used.

I tried several ways to implement those into this use case scenario but all turned out with syntax errors.

In need of advice, please.

juniortan
  • 196
  • 1
  • 1
  • 10
  • I dont know what you want to do, but you have an observable there, not a promise. What is your question? – Alan Grosz Feb 09 '18 at 04:31
  • @AlanGrosz I have a variable **user** which is assigned with the data in **userData()**. But it's undefined when console log within the constructor – juniortan Feb 09 '18 at 04:38
  • where exactly you want to access `this.user`? in the constructor? – Suraj Rao Feb 09 '18 at 04:44
  • @SurajRao accessing on other page by importing `import {ShareService } from '../../providers/share-service/share-service'` and then getting by calling `shareService.getUser();` – juniortan Feb 09 '18 at 05:07
  • check my answer.. call `getUser().then(data=> //in here)` – Suraj Rao Feb 09 '18 at 05:07

2 Answers2

2

Angular provides Async Pipe for this type of Async methods.

user information will be come from firebase server, and it will take time.
in the meanwhile, javascript continues its execution.

that's why you got this.user as undefined, because when JS execute that line, data is not come from server and not assign to it.

so we need to handle this type of methods either by

so try this

share-service.ts

export class ShareService {
 uid: string;

 constructor(public db: AngularFireDatabase) {
 let currentUser = firebase.auth().currentUser;
 this.uid = currentUser.uid;
 }

 getUser() {
   return this.db.object(`users/${this.uid}`)
     .snapshotChanges()
     .map(data => data.payload.val());
 }
}

profile.ts

export class ProfilePage {
 user;

 constructor(public navCtrl: NavController, public firebaseService: 
  FirebaseService, shareService: ShareService) {
  this.user = shareService.getUser();
 }
}

In Template

<div *ngIf="user | async as _user; else loadingUsers">
  {{_user.username}}
</div>
<ng-template #loadingUsers>
  Loading...
</ng-template>
Praveen Soni
  • 771
  • 8
  • 21
1

Here is how you read it..

 userData() {
    return this.db.object(`users/${this.uid}`).snapshotChanges()
    .pipe(map(data => {

      this.user = data.payload.val();
      return this.user;
      console.log('[userData]user: ', this.user);
    }));//import { map } from 'rxjs/operators/map';

}

If you want to access it anywhere use subscribe() on getUser().

  getUser(){
    if(!this.user){
        return this.userData();//return the db call if not set
    }else{
    return of(this.user);//import {of} from 'rxjs/Observable/of;'
  }

In constructor,

  constructor(public db: AngularFireDatabase) {
    let currentUser = firebase.auth().currentUser;
    this.uid = currentUser.uid;
    this.getUser().subscribe(u=>{
        console.log('[constructor]user: ', u);
    });//subscribe to the observable.
  }
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • It's not working, console.log not even getting called. How do i do it with async/await instead? – juniortan Feb 09 '18 at 05:20
  • what do you mean not getting called? any console errors? – Suraj Rao Feb 09 '18 at 05:20
  • no error at all.. console.log inside **.then** is not executed. – juniortan Feb 09 '18 at 05:23
  • sorry. my bad.. it is `return Promise.resolve(this.user);` – Suraj Rao Feb 09 '18 at 05:25
  • Still the same.. `userData() { return this.db.object(`users/${this.uid}`).snapshotChanges().toPromise().then(data => this.user = data.payload.val(); console.log('[userData]user: ', data.payload.val()); return this.user; })}` console.log inside userData() i also not being executed. – juniortan Feb 09 '18 at 05:31
  • you are missing a return somewhere – Suraj Rao Feb 09 '18 at 05:32
  • sorry accidentally submitted my comment earlier without completing what i was going to type. can you read my previous comment again. – juniortan Feb 09 '18 at 05:38
  • then its something to do with db call... otherwise try chaining observables – Suraj Rao Feb 09 '18 at 05:43
  • i was able to get the correct data within userData() in the initial code. – juniortan Feb 09 '18 at 05:58
  • ok... then ytou need to chain observables.. `toPromise()` is not working with angularfire2 for some reason.. what is your rxjs version? – Suraj Rao Feb 09 '18 at 06:05
  • "rxjs": "^5.5.6" – juniortan Feb 09 '18 at 06:27
  • Typescript error `The 'this' context of type 'void' is not assignable to method's 'this' of type 'Observable<{}>'.` at `userData()` – juniortan Feb 09 '18 at 10:11
  • did you specify a return type for the function? – Suraj Rao Feb 09 '18 at 10:12
  • I did as you instructed. [this is my code](https://github.com/tanjunior/ionic3app) – juniortan Feb 09 '18 at 12:01
  • more details of the typescript error [https://github.com/tanjunior/ionic3app/issues/1](https://github.com/tanjunior/ionic3app/issues/1) – juniortan Feb 09 '18 at 12:15
  • ok.. got it... change import of map to `import { map } from 'rxjs/operators';` to use pipeable operator. and also you are missing a return in that function. More [here](https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md) – Suraj Rao Feb 09 '18 at 12:22
  • `import { map } from 'rxjs/operators/map'; you forgot an `s` – Suraj Rao Feb 09 '18 at 12:29
  • Oh you are right, didn't see the **s** behind. no more error now, but doesn't solve the asynchronous issue. kinda back to square one? [https://github.com/tanjunior/ionic3app/issues/2](https://github.com/tanjunior/ionic3app/issues/2) – juniortan Feb 09 '18 at 13:31
  • you cant console log _outside subscribe_.. do it inside.read up on rxjs and asynchronous programming – Suraj Rao Feb 09 '18 at 13:33
  • i did a console log to test, because {{ user.username }} is not showing up on my view. – juniortan Feb 09 '18 at 13:39
  • view may load before you receive data in class variable.. put as `{{user?.username}}` – Suraj Rao Feb 09 '18 at 14:04