Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 Subscribe method call multiple times

im creating a global modal component. My problem is when i call the subscribe method it call multiple times base on the number of the modal was called. How can i prevent mutiple calls on observable subscribe method? Please check my code below. Thanks in advance.

modal.model.ts

export class Modal {
  title: string;
  message: string;
  visible: boolean = false;
}

modal.service

import { Injectable } from '@angular/core';
import { Modal } from './modal.model';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class ModalService {
  static readonly YES = 1;
  static readonly NO = 0;

  private modal = new Modal();
  private subject = new Subject<Modal>();
  private action = new Subject<number>();

  confirmationDialog(message) {
    this.modal.title = 'Confirmation';
    this.modal.message = message;
    return this;
  }

  show() {
    this.modal.visible = true;
    this.setModal(this.modal);
    return this;
  }

  setAction(action: number) {
    this.action.next(<number>action);
  }

  getAction(): Observable<any> {
    return this.action.asObservable();
  }

  setModal(alert: Modal) {
    this.subject.next(<Modal>alert);
    return this;
  }

  getModal(): Observable<any> {
    return this.subject.asObservable();
  }
}

modal.component

import { Component, OnInit } from '@angular/core';
import { ModalService } from './modal.service';
import { Modal } from './modal.model';

@Component({
  selector: 'modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {
  public modal: Modal;

  constructor(private modalService: ModalService){}

  ngOnInit() {
    this.modalService.getModal().subscribe((modal: Modal) => {
      this.modal = modal;
      console.log(modal);
    });
  }

  no() {
    this.modalService.setAction(0);
    this.modalService.close();
  }

  yes() {
    this.modalService.setAction(1);
    this.modalService.close();
  }
}

calling the modal component

showModal() {
  this.modalService.confirmationDialog('Are you sure you want to save this record?').show();
  this.modalService.getAction().subscribe(response => {
    if(response === ModalService.NO) {
      return;
    }
    console.log('call mutiple times');
  });
}

Here is the screenshot of the output on the console log. console log output

like image 705
Juan Avatar asked Jan 30 '23 22:01

Juan


1 Answers

I think i would be easier to use the async pipe inside your modal component:

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

import { ModalService } from './modal.service';
import { Modal } from './modal.model';

@Component({
  selector: 'modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent {
  public modal$: Observable<Modal>;

  constructor(private modalService: ModalService){
      this.modal$ = this.modalService.getModal();
  }

  no() {
    this.modalService.setAction(0);
    this.modalService.close();
  }

  yes() {
    this.modalService.setAction(1);
    this.modalService.close();
  }
}

and inside your template for example:

(modal$ | async)?.title

This ensures that Angular is cleaning up the subscription by itself on component destruction.

For your subscription when creating the modal you can use the take Operator, which completes the subscription if x values where emitted.

this.modalService.getAction().take(1).subscribe(response => {
    if(response === ModalService.NO) {
      return;
    }
    console.log('call mutiple times');
});

I'm assuming you only want 1 value (as its a simple dialog).

like image 146
cyr_x Avatar answered Feb 01 '23 11:02

cyr_x