2
votes

Comment arrêter l'intervalle dans Angular 7?

J'ai une fonction qui émet des valeurs en continu.

Ce que je veux ??

Si la condition Math.sign est remplie, je redirige l'utilisateur vers un autre écran et affiche un message toast.

Mais pour le moment, le message toast est affiché en continu, car l'intervalle est continu.

Ce que j'ai essayé?

this.subscription.unsubscribe () dans la condition if (Math.sign) , mais cela n'a pas fonctionné.

Toutes les suggestions sur la façon d'arrêter l'intervalle le code suivant ??

startTimer(validUntil: string) {
    this.counter$ = interval(1000).pipe(
        map((x) => {
            this.diff = Math.floor((new Date(validUntil).getTime() - new Date().getTime()) / 1000);

            if (Math.sign(this.diff) == -1) {
                //Tried this.subscription.unsubscribe() here

                // Redirects me to another component
                this.goBack(true);
            }
            return x;
        }));

    this.subscription = this.counter$
        .subscribe((x) => {
            this.message$ = this.dhms(this.diff);
        });
}


goBack(requestExpired: boolean) {
    if (requestExpired == true) {
        this.messageDialogService.presentToast('Expired')
    }
    this.router.navigate(['mypage']);
}


4 commentaires

Où appelez-vous this.subscription.unsubscribe () ?


@martin Dans ma condition if (Math.sign)


Donc ça n'a probablement jamais été appelé


La fonction après cette ligne est appelée et je suis redirigé vers un autre écran. Donc, cette ligne est au-dessus et elle doit avoir été appelée ...


5 Réponses :


1
votes

Avez-vous essayé de vous désinscrire dans la méthode ngOnDestroy ?


4 commentaires

pouvez-vous essayer ça? après la redirection, votre composant sera détruit et vous pourrez donc vous désinscrire dans cet événement du cycle de vie


Je viens d'essayer et ça ne marche pas non plus: | Je continue à porter des toasts en continu


l'interface OnDestroy est-elle implémentée?, voici le brouillon que j'ai fait avec un console.log stackblitz.com/edit/angular-hmmavu?file=src/app/...


La combinaison de ngOnDestroy et de validUntil (par Vahid) a aidé. Merci



2
votes

À mon avis, takeWhile avec la condition à l'intérieur est l'approche la plus évidente.

Par exemple:

<div>{ messages$ | async }</div>

REMARQUE : Pourtant, je doute que vous ayez besoin du counter $ . Vous ne pouvez utiliser que le flux message $ avec un tube asynchrone, par exemple

controller

startTimer(validUntil) {
  this.messages$ = interval(1000).pipe(
    // ...
  )
}

template

startTimer(validUntil) {
  this.counter$ = interval(1000).pipe(

    // turn value emissions into diffs
    map(() => Math.floor((new Date(validUntil).getTime() - new Date().getTime()) / 1000)),

    // this is needed to terminate when condition is met
    takeWhile(diff => Math.sign(diff) !== -1),

    // when terminated on conditions -- navigate back
    finalize(()=>{
      this.goBack(true);
    })

    // just in case if user navigates out before condition is met
    takeUntil(this.destroy$)
  )
  .subscribe(diff => {
    this.message$ = this.dhms(diff);
  });
}

J'espère que cela vous aidera


0 commentaires

1
votes

Je pense que le meilleur moyen est d'utiliser takeUntil pipe. Regardez cet exemple .

J'ai réécrit votre code en utilisant le tube takeUntil et filter . Et j'ai déplacé la fonction goBack vers le rappel complete de la fonction d'abonnement.

startTimer(validUntil: string) {
  this.counter$ = interval(1000);
  const takeUntil$ = this.counter$.pipe(
    filter(x => {
      this.diff = Math.floor((new Date(validUntil).getTime() - Date.now()) / 1000);
      return Math.sign(this.diff) === -1;
    })
  );
  this.counter$.pipe(takeUntil(takeUntil$)).subscribe(
    x => {
      this.message$ = this.dhms(this.diff);
    },
    undefined,
    () => {
      this.goBack(true);
    }
  );
}


8 commentaires

Toujours le même toast continu


@MariumMalik Veuillez enregistrer Math.sign (this.diff) === -1 dans le tube filter pour voir si cela devient vrai.


Oui, après quelques valeurs, c'est -1 et devient vrai


@MariumMalik Donc, la méthode this.goBack devrait être appelée. Si elle est appelée et que vous recevez toujours des messages toast, alors il y a un problème avec cette ligne: this.message $ = this.dhms (this.diff); . Je n'ai aucune idée de ce que fait cette ligne.


Oui, la fonction est appelée et je suis renvoyé vers un autre composant avec des toasts continus


this.dhms renvoie juste une valeur au format heure et est utilisé dans mon composant (donc il n'a pas de lien)


@MariumMali. Je ne sais pas comment fonctionne this.message $ mais peut-être si vous mettez this.message $ .unsubscribe () avant this.goBack Ça marche.


La combinaison de ngOnDestroy (suggéré par une autre personne) et de validUntil a aidé. Merci



0
votes

Autant que je sache, la fonction intervalle cesse d'émettre après la désinscription, j'ai également créé un exemple stackblitz pour le démontrer.

Pour une raison quelconque, votre code n'appelle pas la méthode unsubscribe , et je vous conseille de rechercher le problème ici, peut-être en ajoutant un débogueur avant d'appeler unsubscribe pour vérifier s'il est réellement exécuté.

Vérifiez également que vous appelez unsubscribe sur le bon objet, il doit s'agir de subscription et non de timer $ , par exemple.

Mais je pense qu'il n'y a aucun doute que le problème vient du code que vous avez montré.


0 commentaires

0
votes

En fait, il semble que vous ayez besoin de régler un minuteur pour une durée donnée, essayez

startTimer(validUntil) {
   // duration in seconds till invalid
  const duration = Math.floor((new Date(validUntil).getTime() - Date.now()) / 1000));

  this.messages$ = timer(0, 1000).pipe(
    // we take 1 more emission to encompass starting emission
    take(duration + 1)

    // once given number of seconds passed -- navigate back
    finalize(()=>{
      this.goBack(true);
    })

    // just in case if user navigates out before condition is met
    // this is needed if you wont use |async pipe
    takeUntil(this.destroy$)

    // map to display time
    map(value => this.dhms(duration - value))
  );
}

N est la différence en secondes entre l'heure actuelle et validUntil . Donc

timer(0, 1000).pipe(
  take(N)
)

Et puis appliquer | async conduit au message $ dans le modèle.

J'espère que cela vous aidera


0 commentaires