web-dev-qa-db-fra.com

angular 2: utiliser un service pour diffuser un événement

J'essaie d'obtenir un clic de bouton dans un composant pour mettre l'accent sur un élément d'un autre composant. (Franchement, je ne comprends pas pourquoi cela doit être si complexe, mais je n'ai pas été en mesure de mettre en œuvre une méthode plus simple qui fonctionne réellement.)

J'utilise un service. Il n'a pas besoin de transmettre de données sauf que le clic s'est produit. Je ne sais pas comment le composant d'écoute est censé répondre à l'événement.

app.component:

Passer au contenu principal

import { Component } from '@angular/core';
import { SkipToContentService } from './services/skip-to-content.service';


export class AppComponent {
    constructor(
        private skipToContent: SkipToContentService
    ) {}
    }

    skipLink() {
        this.skipToContent.setClicked();
    }

}

composant de connexion:

<input type="text" name="username" />


import { Component, OnInit } from '@angular/core';
import { SkipToContentService } from '../../../services/skip-to-content.service';

export class BaseLoginComponent implements OnInit {

    constructor(
        private skipToContent: SkipToContentService
        ) {
    }

    ngOnInit() {
        this.skipToContent.skipClicked.subscribe(
            console.log("!")
            // should put focus() on input
        );

    }
}

skip-to-content.service:

import { Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class SkipToContentService {

    skipClicked: EventEmitter<boolean> = new EventEmitter();


    constructor() {
    }

    setClicked() {
        console.log('clicked');
        this.skipClicked.emit();
    };
}

Je suis un peu perdu ici quant à la façon dont la connexion "entendra" l'événement skipClicked.

18
DaveC426913

Faites juste un petit changement dans votre méthode setClicked ():

this.skipClicked.next (true);

au lieu de this.skipClicked.emit();

Modifiez votre abonnement en:

this.skipToContent.skipClicked.subscribe( value => {
    if (value === true) {
        console.log("!"); 
        // should put focus() on input 
    }
});

Cela résoudra votre problème.

14
Faisal

EventEmitter ne doit être utilisé que dans un composant réel avec une directive @Output. Tout le reste pourrait ne pas fonctionner à l'avenir.

Pour la communication enfant-parent, il est préférable d'utiliser un objet ou un sujet comportemental. Ceci est un exemple du guide angular.

https://angular.io/guide/component-interaction

@Injectable()
export class MissionService {

  // Observable string sources
  private missionAnnouncedSource = new Subject<string>();
  private missionConfirmedSource = new Subject<string>();

  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();

  // Service message commands
  announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);
  }

  confirmMission(astronaut: string) {
    this.missionConfirmedSource.next(astronaut);
  }
}

Pointe:

Si vous avez un événement qui signifie simplement que quelque chose s'est produit ou terminé - et qu'aucune donnée réelle ne lui est associée - vous pouvez utiliser une Subject<void>(). Cela rend la signature de next() plus propre et vous n'avez pas besoin de fournir une valeur fictive pour le plaisir.

Par exemple.

windowClosed = new Subject<void>();

windowClosed.next() va émettre l'événement

11
Simon_Weaver