How can I detect service variable change when updated from another component?

后端 未结 2 1603
伪装坚强ぢ
伪装坚强ぢ 2020-12-07 14:12

I\'m trying to get the updated value from a service variable (isSidebarVisible) which is keeps on updated by another component (header) with a clic

2条回答
  •  感情败类
    2020-12-07 14:46

    @isherwood put me on the track, thanks! This was the question and answer that looked the most like my situation.

    In my case, I have an app-wide userService that listens to changes in AngularFireAuth (authState) and when a valid user exists, it sets up a listener to that user's AngularFirestore document, containing the user's info like name, email, color, whatever (/appusers/${user.id}). All the pages that need anything from userService get those data live, since it's a listener ( .subscribe() )

    My problem was that pages relying on the user document being ready (logged in and user document fetched) before going on to do more database stuff. When navigating straight to an internal page via deep links, the page would try to do database things before the user doc was ready, leading to error/crash.

    Following @isherwoods instructions above, this is how I make sure my app's pages wait for the user data to be ready before trying to do additional database things with it:

    user.service.ts

    export class UserService {
    
    userDocumentReady: boolean = false; // initial value is "userdoc is not ready"
    userDocObserver: Subject = new Subject(); // observing that bool
    
    constructor(
      public fireauth: AngularFireAuth,
      public afs: AngularFirestore,
    ) {
    
    // watch variable
    this.userDocObserver.subscribe(value => this.userDocumentReady = value);
    
    this.fireauth.authState
      .subscribe(user => {
        if (user) {
    
          this.afs.doc(`/tooluser/${user.uid}`).snapshotChanges()
          .subscribe(usr => {
            if (usr.payload.data()) {
              console.log(`got user object from database:`, usr.payload.data());              
              this.currentUser = usr.payload.data();
    
              this.userDocObserver.next(true); // flip UserDocumentReady flag
    

    mytools.page.ts

    // this is a logged-in page of the app,
    // accessible through deep link https://my.app.domain/mytools
    
    export class UsersPage implements OnInit {
    
    constructor(
      public userService: UserService,
    ) { }
    
    ngOnInit() {
      if (this.userService.userDocumentReady) {
        console.log(`users: userdoc already here, no need to wait`);
        this.setupPageData();
        return;
      }
    
      // wait for userdoc before setting up page
      this.userService.userDocObserver.subscribe(docReady => {
        if (docReady){
          console.log(`mytools: user ready value ${docReady}. now setup page.`);
          this.setupPageData(); // this function does the database stuff that depends on the user data to be ready first
        }
      });
    }
    

    This "worksforme" now and behavior seems consistent. Also very handy when developing, as typing a URL in the browser bar causes this kind of direct navigation. Writing this to remember it - and who knows if it can be useful to others?

    This is only my second ionic app, so if something is horribly wrong with my structuring/setup, I'm very much interested in comments on this solution :)

    edit: added check in mytools.page.ts so that we won't wait (forever) on a new user doc if one already exists

提交回复
热议问题