1
votes

I have the following denormalized Firebase structure:

members
  -memberid1
    -threads
       -threadid1: true,
       -threadid3: true
    -username: "Adam"
    ...

threads
  -threadid1
      -author: memberid3
      -quality: 67
      -participants
         -memberid2: true,
         -memberid3: true
      ...

And I'm listing threads ordered by quality in my component:

featured-threads.component.ts

constructor(af: AngularFire) {
    this.threads = af.database.list('/threads', {
        query: {
            orderByChild: 'quality',
            endAt: 10
    }
});

Here's an excerpt from my view:

featured-threads.component.html

<div *ngFor="let thread of threads | async" class="thread-tile">
...
    {{thread.author}} //Renders memberid3
...
</div>

Instead of rendering memberid3 here, I'd like to get the corresponding member's username property value.

The solutions here and here both get their observables outside of the constructor, instead of inside as demonstrated in the Angularfire2 docs. They use this.af.database. When I use the this keyword within the constructor, TypeScript warns that it doesn't recognize af as a component property (because it obviously isn't). I can use this outside of the constructor by declaring the property af: Angularfire;, but then I get the console error TypeError: Cannot read property 'database' of undefined, which I assume has to do with the fact that declaring the property isn't the same as injecting the AngularFire service. I've tried some other things that are probably too comical to be relevant to this question, too.

I'm not entirely sure what's happening here. This problem prevents me from creating a method to which I could simply pass the value of author from threads as a parameter. This is because methods can't be defined within the constructor, and outside of the constructor af is null.

I'm not even entirely sure that this addresses the core question. I want to be able to join/nest these observables any time, not just in this simpler case when I have the benefit of a direct path to the memberid. There are a number of questions regarding nesting observables whose solutions don't use Angularfire 2. Unfortunately, I've been unable to translate them to an Angularfire 2 solution.

Update

I moved all the logic I had in the component over to a service and now inject the service's method getFeaturedThreads() into the component with the following:

ngOnInit() {
    this.threads = this.featuredThreadsService.getFeaturedThreads()
    this.threads.subscribe( 
        allThreads => 
            allThreads.forEach(thisThread => {
                this.featuredThreadsService.getUsername(thisThread.author)
                    .subscribe( 
                        username => console.log(username))
            })
    )
}

getUserName() looks like this:

getUsername(memberKey: string) {
    return this.af.database.object('/members/' + memberKey + '/username')
}

For now, this logs the username property for each member to the console. Unfortunately, I only get the key. The values are empty:

enter image description here

... which is strange to me, given the fact that getUsername() is successfully passing the member id's into the query path.

enter image description here

This is a grab from my Firebase console view that shows the path is correct.

enter image description here

I recognize the fact that this is a usage question and not an issue with the tech.

1
If you want to access the af field outside the constructor, add private before it. private af: AngularFire. Now you can do this.af.someMethodSteveadoo

1 Answers

1
votes

I would implement it like this, I moved it to ngOnInit because you really shouldn't be do it in the constructor. Just add private before your af declaration in your constructor.

public ngOnInit() {
    this.threads = this.af.database.list('/threads', {
        query: {
            orderByChild: 'quality',
            endAt: 10
        }
    }).do(threads => {
        threads.forEach(thread => {
            thread.author = this.af.database.getName(thread.author); //actual method to get the username
        });
    });
}

And your component html

<div *ngFor="let thread of threads | async" class="thread-tile">
...
    {{thread.author | async}}
...
</div>