0

I'm sorry if the title is a bit wrong, but the reason I'm posting this question here is because's I'm kinda in the dark, and can't find what I'm looking for online. I also don't really know exactly what I'm looking for.

So I have an angular app, and I'm using Firestore as a database. So I'm using this piece of code to get my collection in a service:

this.userAsteroid$ = this.afs.collection<UserAsteroid>(this.collection).valueChanges();

I then have a function in the serivce that returns this.userAsteroid$. Then, in my component, in my ngOnInit, I have this:

this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.asteroidId == this.id && document.userId == this.user.uid) {
      this.hasAsteroid = true;
      console.log("test: ", this.hasAsteroid);
    }
    console.log(document);
  });
});

So basically, my component is the detail page for a specific asteroid, and when my collection has a document that includes the asteroid id and the id of the user that is logged in, I want my bool hasAsteroid to be put on true.

This is the html for the component:

    <div [hidden]="loading">
  <div class="columns" *ngIf="!hasAsteroid && user">
    <div class="column">
        <button class="button is-primary is-outlined" type="button" (click)="addAsteroid(id)">Add to my asteroids</button>
    </div>
  </div>

Now, this works, but only when I reload the page, not when I navigate to it. I suspect this has something to do with the fact that the subscribe function I'm using is not async, and thus sometimes my page is loaded before the bool has been put on true, and then my *ngIf that uses the bool doesn't work.

I've tried to use .pipe and then map, as I would do with JSON data I receive from an API, but this doesn't do anything in this case.

In another component, I'm using the same function from the service to this time get all the asteroids that one user has saved, like this:

getUserFeed() {
this.authService.userData$.subscribe(data => this.user = data);
this.userAsteroid$ = this.userAsteroidService.getAsteroids();

this.userAsteroid$.subscribe(asteroids => {
  asteroids.forEach(document => {
    if (document.userId == this.user.uid) {
      console.log(document.asteroidId);
      this.dataArray.push(document.asteroidId);
    }
  });
})}

As you can see, I'm pushing all of the asteroid ids that the user has saved into an array, so I can later use them to do an api call.

I didn't bother to write the rest of the code here, because I know it won't work because of the function not being async.

If anyone has a solution, or can point me to the right documentation I need for this to work, I'd be extremely grateful.

EDIT:

After further working on this in class, I solved part of this problem and was able to determine where the problem lies more accurately, however the problem still persists. In both functions I showed initially, I have a part where I use this code block

this.authService.userData$.subscribe(data => {
  this.user = data;

  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.asteroidId == this.id && document.userId == this.user.uid) {
        this.hasAsteroid = true;
        console.log("test: ", this.hasAsteroid);
      }
      console.log(document);
    });
  });
});

Basically I'm subscribing to my authSerivce to determine my user, in that subscription I subscribe to my firestore service and then I do some stuff.

This all works when I initially load my component. However I use parameters in my routes to sort of work with "tabs". I subscribe to these parameters in my ngOnit so that when I click a link in my navigation my page will update the component with the right parameter. In this subscription I then recall my function.

However, when I recall the function, it will still subscribe to the user, it will still get the observable from firestore, but it won't subscribe to the observable again. Basically, everything from this line down doesn't work when I recall the function:

this.userAsteroid$.subscribe(asteroids => {

Anyone have an idea why?

2
  • As far as I understand your setup, that should work. Please show the corresponding component html code. Commented Nov 12, 2018 at 16:27
  • I added it to the question Commented Nov 12, 2018 at 16:36

2 Answers 2

3

You need to launch your request on asteroids only after you got the user id. So your code should be inside the subscribe result of user data.

Otherwise, it depends of the order in which you receive the response: if you get the asteroids before, then this.user is not set yet.

You can see that with console.log in each event handler, and it should be obvious.

Thus, your code would become:

getUserFeed() {
this.authService.userData$.subscribe(data => {
  this.user = data;
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();

  this.userAsteroid$.subscribe(asteroids => {
    asteroids.forEach(document => {
      if (document.userId == this.user.uid) {
        console.log(document.asteroidId);
        this.dataArray.push(document.asteroidId);
      }
    });
  });});
}
Sign up to request clarification or add additional context in comments.

3 Comments

Hey man, thanks for the answer! I still have one problem tho, I edited my initial question (at the bottom under 'EDIT'). Could you have a look at it?
I think it still subscribe, there is little doubt about that. Try putting console.log('I am here') statements around your code to see what is executed when. Maybe yo have to wait for document to be ready, try putting your code in NgAfterViewInit instead of NgOnInit.
But anyway, don't do that on SO: this post solves your initial problem so you should accept as an answer. If you have another problem, open a new question. This way, questions/answers stay understandable for people googling later.
1

How about moving the document lookup into the auth subscription?

getUserFeed() {
  this.authService.userData$.subscribe(data => {
    this.user = data
    this.userAsteroid$.subscribe(asteroids => {
      asteroids.forEach(document => {
        if (document.userId == this.user.uid) {
          console.log(document.asteroidId);
          this.dataArray.push(document.asteroidId);
        }
      });
    })}
  });
  this.userAsteroid$ = this.userAsteroidService.getAsteroids();
}

This way you're guaranteed that the userAsteroid$ subscription will only be set up after the this.user is available.

If you go this route, you'll probably want to detect if you've already subscribed to this.userAsteriud$ and skip resubscribing in that case.

2 Comments

This seems to work. However, now, when I reload the page, it displays each asteroid twice. Is this because I'm already subscribed? Also, I don't now exactly how to skip resubscribing, could you maybe point me to some documentation? I'm not very experienced with subscribing, ...
Subscriptions don't survive page reloads, so that shouldn't be it. I'm honestly not an expert in these specific subscriptions either, but the AngularFire docs should contain all you need: github.com/angular/angularfire2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.