2

I'm trying to display a list of rooms using Angular 4 async pipe and an Observable created with new Observable().

I have a RoomService defined like this:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { DatabaseService } from '../core/database.service';
import { Room } from './room';

@Injectable()
export class RoomService {
  private store: any;

  constructor(private db: DatabaseService) {
    this.store = this.db.store('rooms');
  }

  getRooms(query: any = {}): Observable<Room[]> {
    return new Observable(observer => {
      this.store.find(query, (error, results) => {
        if (error) {
          observer.error(error);
        } else {
          const rooms = results.map(room => {
            return new Room(room.building, room.number, room._id);
          });
          observer.next(rooms);
        }
        observer.complete();
      });
   });
  }
}

and a RoomListComponent defined like this:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import { Room } from '../room';
import { RoomService } from '../room.service';

@Component({
  selector: 'app-room-list',
  templateUrl: './room-list.component.html',
  styleUrls: ['./room-list.component.scss']
})
export class RoomListComponent implements OnInit {
  rooms$: Observable<Room[]>;

  constructor(private roomService: RoomService) {}

  ngOnInit() {
    this.rooms$ = this.roomService.getRooms();
  }
}

And I'm trying to display rooms like this:

<h1>Rooms</h1>
<div *ngIf="$rooms | async as rooms; else loading">
  <div *ngFor="let room of rooms">
    {{ room.number }}
  </div>
</div>
<ng-template #loading>Loading...</ng-template>

But it's not working. The view keep showing Loading... Please can anyone tell me what's wrong with my code?

2
  • I think it can be a syntax error. It should be <div *ngIf="rooms$ | async as rooms; else loading"> on the template. Commented Dec 12, 2017 at 7:14
  • You shouldn't change your question after it has been answered. It ruins the context of the answer. Commented Sep 15, 2020 at 2:51

1 Answer 1

9

Don't call method in template because it will be returning new observable every change detection tick.

You could try this:

rooms$: Observable<Room[]>;

constructor(private roomService: RoomService) {}

ngOnInit() {
  this.rooms$ = this.roomService.getRooms()
}

view.html

<div *ngIf="rooms$ | async as rooms; else loading">

Plunker Example enter image description here

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for your answer. I've changed the code as you suggested but it's still not working, the view keep showing Loading...
Then i want to see a reproduction. Do you have any github repo to reproduce it?
Try to set debugger front of observer.next(rooms);
Here is the repo: github.com/valerymelou/pharaoh-bills. Checkout the branch feature/rooms
Because you don't have any entry in your database. And even if the service returns [] array it should render the empty <ul></ul> tag. It seems like async doesn't automatically subscribe to the observer as it's supposed to.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.