0

I have a very simple Angular app - a nav bar, a sidebar and a main area.

enter image description here

I am using a data service to get the data for the cards in the main area.

Here is the code for the data service:

import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
// Models
import { Card } from "../models/card";
import { Filter } from "../models/filter";

const httpOptions = {
  headers: new HttpHeaders({ "Content-Type": "applicaiton/json" })
};

@Injectable({
  providedIn: "root"
})
export class DataService {
  getCardsUrl: string = "http://ip_address:3000/api/data/cards/";
  getTimeframesUrl: string = "http://ip_address:3000/api/data/timeframe/";
  constructor(private http: HttpClient) {}

  getCardsData(): Observable<Card[]> {
    return this.http.get<Card[]>(this.getCardsUrl);
  }

  getTimeframeFilters(): Observable<Filter[]> {
    return this.http.get<Filter[]>(this.getTimeframesUrl);
  }
}

I am subscribing to the data service inside the ngOnInit lifecycle hook in main.component.ts.

Here is the code for main.component.ts

import { Component, OnInit } from "@angular/core";
import { DataService } from "../../services/data.service";
import { Card } from "../../models/card";

@Component({
  selector: "app-main",
  templateUrl: "./main.component.html",
  styleUrls: ["./main.component.css"]
})
export class MainComponent implements OnInit {
  cards: Card[];
  loaded: boolean;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.loaded = false;

    setTimeout(() => {
      this.dataService.getCardsData().subscribe(cards => {
        this.cards = cards;
        this.loaded = true;
      });
    }, 2000);
  }
}

Question: I want to update the contents of main based on the timeframe selection in the sidebar. How do I go about doing this? I am new to Angular, so maybe I am not understanding how Observables work. Can I please have some directions?

KalC
  • 1,530
  • 3
  • 22
  • 33

1 Answers1

1

You have to set an action to the button an call the services again

import { Component, OnInit } from "@angular/core";
import { DataService } from "../../services/data.service";
import { Card } from "../../models/card";

@Component({
  selector: "app-main",
  templateUrl: "./main.component.html",
  styleUrls: ["./main.component.css"]
})
export class MainComponent implements OnInit {
  cards: Card[];
  loaded: boolean;

  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.loaded = false;

    setTimeout(() => {
       this.getCards();
    }, 2000);
  }

  getCards(timeframe?) {
     this.dataService.getCardsData(timeframe).subscribe(cards => {
        this.cards = cards;
        this.loaded = true;
     });
  }

  applyFilter(timeframe) {
      this.getCards(timeframe);
  }
}

Add the applyFilter action on the (click) button event with the new value. Maybe the timeframe could be binding with ngModel

Alan Grosz
  • 1,175
  • 10
  • 15
  • 1
    I think this approach will create a new subscription every time the user changes the time. Which is a potential memory leak. `this.dataService.getCardsData(timeframe).pipe(take(1))...` should solve the issue. Or using async pipe in the template. – igor_c Aug 15 '19 at 20:06
  • @igor_c HttpClient's get how many times emit (without take(1) ) ? – robert Aug 15 '19 at 20:28
  • 1
    @igor_c That's not an issue with HttpClient. Angular handles the clean-up automatically. See [this SO](https://stackoverflow.com/questions/35042929/is-it-necessary-to-unsubscribe-from-observables-created-by-http-methods). – Rich Aug 15 '19 at 20:47
  • 1
    @Rich didn’t know about the HttpClient trick but still a lot of people in that thread write that you should always unsubscribe because user can leave the page thus destroy the component before the request is completed. So I think unsubscribing makes sense and doesn’t hurt even in that scenario. – igor_c Aug 15 '19 at 21:00