问题
I'm trying to get a button click in one component to put focus on an element on another component. (Frankly, I don't understand why this must be so complex, but I have not been able to implement any simpler way that actually works.)
I'm using a service. It doesn't need to pass any data except that the click occurred. I'm not sure how the listening component is meant to respond to the event.
app.component:
Skip to main content
import { Component } from '@angular/core';
import { SkipToContentService } from './services/skip-to-content.service';
export class AppComponent {
constructor(
private skipToContent: SkipToContentService
) {}
}
skipLink() {
this.skipToContent.setClicked();
}
}
login component:
<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();
};
}
I'm a bit lost here as to how logon will "hear" the skipClicked event.
回答1:
First of all, use a BehaviorSubject
instead of EventEmitter
. Change the declaration of skipCliekd
to the following:
skipClicked: BehaviorSubject<boolean> = new BehaviorSubject(false);
Then, you need to broadcast the new value using next()
method as following:
this.skipClicked.next (true);
Also, change your subscription to:
this.skipToContent.skipClicked.subscribe( value => {
if (value === true) {
console.log("!");
// should put focus() on input
}
});
回答2:
EventEmitter should only be used in an actual component with an @Output directive. Anything else may not work in future.
For child-parent communication it is better to use a Subject or BehaviorSubject. This is an example from the angular guide.
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);
}
}
Tip:
If you have an event that just signifies something has occurred or completed - and has no actual data associated with it - you can use a Subject<void>()
. This makes the signature of next()
cleaner and you don't need to provide a dummy value for the sake of it.
Eg.
windowClosed = new Subject<void>();
windowClosed.next()
will emit the event
来源:https://stackoverflow.com/questions/45446724/angular-2-using-a-service-to-broadcast-an-event