Angular 2: использование службы для трансляции события

Я пытаюсь получить щелчок кнопки в одном компоненте, чтобы сосредоточить внимание на элементе на другом компоненте. (Честно говоря, я не понимаю, почему это должно быть настолько сложно, но я не смог реализовать какой-либо более простой способ, который действительно работает.)

Я использую услугу. Ему не нужно передавать какие-либо данные, кроме того, что произошел щелчок. Я не уверен, как компонент прослушивания должен реагировать на событие.

app.component:

Перейти к основному содержанию

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


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

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

}

компонент входа:

<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
        );

    }
}

пропуск к 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();
    };
}

Я немного потерял здесь, как вход в систему будет "слышать" событие skipClicked.

Ответ 1

Прежде всего, используйте BehaviorSubject вместо EventEmitter. Измените объявление skipCliekd следующим:

skipClicked: BehaviorSubject<boolean> = new BehaviorSubject(false);

Затем вам нужно передать новое значение, используя метод next() следующим образом:

this.skipClicked.next (true);

Также измените подписку на:

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

Ответ 2

EventEmitter должен использоваться только в реальном компоненте с директивой @Output. Все остальное может не сработать в будущем.

Для общения между родителями и детьми лучше использовать Subject или BehaviorSubject. Это пример из 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);
  }
}

Совет:

Если у вас есть событие, которое просто означает, что что-то произошло или завершено - и не имеет фактических данных, связанных с ним - вы можете использовать Subject<void>(). Это делает подпись next() более чистой, и вам не нужно указывать фиктивное значение ради нее.

Например.

windowClosed = new Subject<void>();

windowClosed.next() отправит событие