简体   繁体   中英

Angular 6 - observable subscription doesn't work

I have the following case. Service as usually is fetching data from the server, and this data needs to be updated in other component.

The component gets subscribed value only once but the service is getting data every 2 seconds. I tested it, and the service is doing it right.

It doesn't in my case if the subscirption is either in ngOnInit or constructor

component:

import {Component, OnInit} from '@angular/core';
import {TaskService} from "../../services/task.service";
import {Task} from "../../models/task";

@Component({
  selector: 'app-tasks',
  templateUrl: './tasks.component.html',
  styleUrls: ['./tasks.component.css']
})
export class TasksComponent implements OnInit {
  tasks: Task[];

  constructor(private taskService: TaskService) {
    this.taskService.getTasks().subscribe(tasks => {  // this is triggered only once, why ?
      this.tasks = tasks;
      console.log(tasks);
    });
  }

  ngOnInit() {

  }

  updateTask(task: Task) {
    try {
      task.completed = !task.completed;
      this.taskService.updateTask(task).subscribe();
    }
    catch (e) {
      task.completed = !task.completed;
    }
  }

}

service:

import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {Observable, of, timer} from "rxjs";
import {Task} from "../models/task";


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


@Injectable({
  providedIn: 'root'
})


export class TaskService {

  tasks: Task[];
  tasksURL = 'http://localhost:8080/api/tasks/';

  constructor(private http: HttpClient) {

    timer(1000, 2000).subscribe(() => {
      this.http.get<Task[]>(this.tasksURL).subscribe(value => this.tasks = value)
    }); // fetches and update the array every 2 seconds
  }

  getTasks(): Observable<Task[]> {
    return of(this.tasks); //returns observable which is than used by the component
  }

  updateTask(task: Task): Observable<Task> {
    const url = `${this.tasksURL}`;

    return this.http.post<Task>(url, task, httpOptions)

  }
}

With your example it is clear that the service gets it every 2 seconds due to

timer(1000, 2000).subscribe(() => {

In the component, your subscribe simply without an interval. As the getTask does not emit an event later, nothing will be updated.

Either use also a timer in the component (not elegant) or emit the .next manually:

In Service:

public myObserver$: Subject<any>;
[...]
constructor(private http: HttpClient) {

  timer(1000, 2000).subscribe(() => {
    this.http.get<Task[]>(this.tasksURL).subscribe(value => {
      this.tasks = value;
      myObserver$.next(this.tasks);
    )}
  }); // fetches and update the array every 2 seconds
}

You can then subscribe to myObserver$ in the service instead of the getTasks() method. You don't need the timer in the component.

You should also store your Subscription in the component to a variable:

private subscriptionRef: Subscription;

constructor(private taskService: TaskService) {
  this.subscription = this.taskService.getTasks().subscribe(tasks => {  // this is triggered only once, why ?
  this.tasks = tasks;
  });
}

so that you can unsubscribe in the ngOnDestroy method.

ngOnDestroy(): void {
  this.subscription.unsubscribe();
}

You can manage to do what you want by using Subject/Behaviour : just some change in your service

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

export class TaskService {

  tasks: new BehaviorSubject<Task[]>([]);
  tasksURL = 'http://localhost:8080/api/tasks/';

  constructor(private http: HttpClient) {

     timer(1000, 2000).subscribe(() => {
       this.http.get<Task[]>(this.tasksURL).subscribe( (value) => { 
         this.tasks.next(value);
       })
     }); // fetches and update the array every 2 seconds
  }

  getTasks(): Observable<Task[]> {
        return tasks.asObservable(); //returns observable which is then used by the component
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM