Search code examples
angulartypescriptrxjsobservablesubscription

Observable need a click to load on html page


I am developing a web application with Angular and I use Observable.
Currently, when I search into the firebase DB I simply make a *ngFor="let myvar of _myvar | async" and my HTML page well displays the data.
But every time a Subject intervenes, my HTML page doesn't display any data until I click on an element of the page...
Here is my code, if someone has an idea : home.component.html

<section>
    <div id="paddingTop" fxLayout="row" fxLayout.lt-md="column" fxLayoutAlign="space-around center">
        <div>
          <h2>*****************</h2>
          <mat-icon>place</mat-icon>
          <mat-form-field color="accent" appearance="fill" id="searchAddress">
            <mat-label>*****************</mat-label>
            <input 
              matInput 
              ngx-google-places-autocomplete #placesRef="ngx-places" 
              (onAddressChange)="handleAddressChange($event)" />
            <button mat-button *ngIf="address" matSuffix mat-icon-button aria-label="Clear" (click)="address=''">
              <mat-icon>close</mat-icon>
            </button>
          </mat-form-field>
        </div>
        <!--
        <div>
          <mat-form-field appearance="fill" color="accent">
            <mat-label>Select</mat-label>
            <mat-select>
              <mat-option value="one">First option</mat-option>
              <mat-option value="two">Second option</mat-option>
            </mat-select>
          </mat-form-field>
        </div>
      -->
    </div>
    <div id="searchPart">
        <h2>*****************</h2>
        <section class="mobile" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="20px" fxHide.lg *ngFor="let id of _feedersId | async">
          <app-feeder-card
            [feederId] = "id"
            [clientId] = "this.uid"
          ></app-feeder-card>
        </section>
        <section *ngIf="feedersId.length == 0" fxLayout="column" fxLayoutAlign="center center" >
          <p>*****************</p>
          <p>
            <mat-icon>arrow_upward</mat-icon>
            *****************
            <mat-icon>arrow_upward</mat-icon>
          </p>
        </section>
    </div>
</section>

home.component.ts

import { Component, OnInit } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { Router } from '@angular/router';
import { Observable, Subject } from 'rxjs';
import { AuthService } from 'src/app/auth/auth.service';
import { Order } from 'src/app/order/order.model';
import { User } from '../user.model';

@Component({
  selector: 'app-user-home',
  templateUrl: './user-home.component.html',
  styleUrls: ['./user-home.component.scss']
})
export class UserHomeComponent implements OnInit {

  orders: Observable<Order[]>; 
  feedersId: Array<string> = [];
  _feedersId: Observable<Array<string>> = this.getFeederArray();
  uid: string;

  constructor(private router: Router, private authService: AuthService, private db: AngularFirestore) {}

  ngOnInit(): void {
    this.getFeederArray().subscribe(r => {
      console.log('tests')
      this.setFeederId(r);
    })
  }

  address = '';

  public handleAddressChange(address: any) {
    console.log(address);
    this.address = address.formatted_address;
    const lat = address.geometry.location.lat();
    const lng = address.geometry.location.lng();
    const adrs = address.formatted_address;

    this.router.navigate(['/search-feeder/', lat, lng, adrs]);
  }
  
  getUser(): Observable<User> {
    return this.authService.getUser().switchMap(user => {
      this.uid = user.uid;
      return this.db.collection('user').doc(user.uid).valueChanges({ idField: 'id' }) as Observable<User>;
    }).map(response => {
      return response;
    });
  }

  getFeederArray(): Observable<Array<string>> {
    let toReturn: Array<string> = [];
    var subject = new Subject<Array<string>>();
    this.getUser().subscribe(user => {
      this.orders = this.db.collection("orders", ref => {
        return ref
        .where("clientId", "==", user.id)
      }).valueChanges({ idField: 'id' }) as Observable<Order[]>;
      this.orders.subscribe(orders => {
        orders.forEach(order => {
          if(toReturn.indexOf(order.feederId) == -1) {
            toReturn.push(order.feederId);
          }
        })
      })
      subject.next(toReturn);
    })
    return subject.asObservable();
  }
  
  setFeederId(ids: Array<string>) {
    this.feedersId = ids;
  }
}


Solution

  • I simplified your getFeederArray function, to return one observable without subscribing to two observables within it.

    Could you please check it now, and try the following:

      getFeederArray(): Observable<string[]> {
        return this.getUser().pipe(
          switchMap((user) => {
            this.orders = this.db
              .collection("orders", (ref) => ref.where("clientId", "==", user.id))
              .valueChanges({ idField: "id" }) as Observable<Order[]>;
    
            return this.orders;
          }),
          map((orders) => orders.map((order) => order.feederId))
        );
      }