Angular 7-如何将事件触发器限制为发生事件的特定组件?

时间:2019-05-28 10:22:38

标签: javascript angular typescript

我有一个文本区域列表:

text-area.component.html

<!--suppress HtmlFormInputWithoutLabel -->
<textarea [ngClass]="generateTextAreaClass()" (keypress)="onKeyPress($event)">{{ value }}</textarea>

文本区域有一个keypress事件。

当我在一个文本区域中按一个键时,它将触发此组件所有实例的keypress事件。

结果,我触发了5个事件。显然,这并不代表我作为用户所做的操作。

{textareaSelector: ".app-utility-textarea-1-1", keypressType: "shift+enter"}
{textareaSelector: ".app-utility-textarea-1-1", keypressType: "shift+enter"}
{textareaSelector: ".app-utility-textarea-1-1", keypressType: "shift+enter"}
{textareaSelector: ".app-utility-textarea-1-1", keypressType: "shift+enter"}
{textareaSelector: ".app-utility-textarea-1-1", keypressType: "shift+enter"}

如何限制仅针对当前输入的文本区域触发事件,以便仅触发一个事件?

@Component({
  selector: 'app-utility-textarea',
  templateUrl: './text-area.component.html',
  styleUrls: ['./text-area.component.scss']
})
export class TextAreaComponent implements AfterViewInit {

  constructor(private eventBus: EventBusService) {
  }

  @Input() value: string;
  @Input() id: string;
  public textAreaClassPrefix = 'app-utility-textarea';

  ...

  generateTextAreaClass(): string {
    return `${this.textAreaClassPrefix}-${this.id}`;
  }

  onKeyPress(event: KeyboardEvent) {
    event.stopPropagation();
    if (event.key === 'Enter' && event.shiftKey) {
      event.preventDefault();
      const textAreaKeyPressEvent: TextAreaKeyPressEvent = {
        textareaSelector: this.generateTextAreaClassCSSSelector(),
        keypressType: TextAreaKeyPressType.SHIFT_ENTER
      };
      this.eventBus.textAreaKeyPressSubject$.next(textAreaKeyPressEvent);
    }
  }
}

event-bus.service.ts

@Injectable()
export class EventBusService {

  public navbarSubject$ = new BehaviorSubject(DashboardNavbarEvent.SIDEBAR_MENU_CLOSED);
  public textAreaKeyPressSubject$ = new Subject<TextAreaKeyPressEvent>();

  constructor() {
  }

}

subscriber.component.ts

@Component({
  selector: 'app-subscriber',
  templateUrl: './subscriber.component.html',
  styleUrls: ['./subscriber.component.scss']
})
export class SubscriberComponent implements OnInit {

  @Input() public block: any;
  @Input() public index: number;

  constructor(private eventBus: EventBusService) {
  }

  ngOnInit() {
    this.eventBus.textAreaKeyPressSubject$.subscribe((event: TextAreaKeyPressEvent) => {
      console.log(event);
    });
  }

}

2 个答案:

答案 0 :(得分:0)

结果证明这是一个设计问题。我正在预订另一个有5个实例的组件中的textAreaKeyPressSubject$。每个实例最终都在init上订阅了textAreaKeyPressSubject$,并分别记录了该事件1次。

keypress事件仅在我输入的textarea.component.ts中触发一次。

当我将对此主题的订阅移动到只有一个实例的父组件时,此问题已解决。

答案 1 :(得分:0)

您正在使用subject中的主题:

  

什么是主题? RxJS主题是一种特殊的Observable类型,它允许将值多播到许多Observer。普通的Observable是单播的(每个订阅的Observer拥有Observable的独立执行),而Subject是多播的。

然后您将在下一个发出事件:

this.eventBus.textAreaKeyPressSubject$.next(textAreaKeyPressEvent);

因此,基本上,您正在向多播订户发送一些内容,因此,可以从正确的一个文本区域触发该事件,如您所见,但您正在将该事件传播给其他订户。关键是您想要一对一的订阅而不是一对多的订阅。希望这会有所帮助