【问题标题】:How to prevent clicks to custom button component in Angular 4如何防止点击Angular 4中的自定义按钮组件
【发布时间】:2018-10-24 10:52:44
【问题描述】:

tl;dr - 我如何让 myButton 组件上的 click() 处理程序来支持按钮的禁用状态?

我有一个自定义按钮组件,用于组件化具有相似外观和感觉的按钮,包括文本和 FA 图标。按钮组件获得某些输入,包括其文本和是否禁用的标志。禁用时,它会正确显示(即变暗和禁止吸烟光标),但其 click() 处理程序始终会收到点击。

我想我知道为什么会发生这种情况,但我不知道如何解决它。我尝试在按钮组件上声明 Output() click = new EventEmitter<any>(),认为 Angular 会以某种方式正确连接它,但那不起作用。

我的按钮的使用者会这样做:

//foo.component.html
...
<my-button
  (click)="saveWidget()"
  [disabled]="shouldBeDisabled"
  type="{{buttonTypes.save}}">
</myButton>
...

//foo.component.ts
import { ButtonTypes } from './myButton';

export class FooComponent implements OnInit {
  buttonTypes = ButtonTypes;

  saveWidget() {
    //do some saving
  }

  get shouldBeDisabled() {
    return true; //Normally a real test in here
  }
  ...
}

我的问题是,当使用此按钮时,无论my-button 的禁用状态如何,都会调用单击处理程序(即 foo.component 上的 saveWidget())。

按钮组件看起来像这样:

export enum ButtonTypes {
  add,
  cancel,
  save,
}

@Component({
  selector: 'my-button',
  template: `<button [type]="tagType"
                [disabled]="disabled"
                [ngClass]="btnClasses">
                  <i *ngIf="hasLeft" class="fa" [ngClass]="iconCls" aria-hidden="true"></i>
                  <span class="hidden-xs hidden-sm">{{text}}</span>
                  <i *ngIf="hasRight" class="fa" [ngClass]="iconCls" aria-hidden="true"></i>
              </button>`
})
export class ButtonComponent implements OnInit {
  @Input() disabled = false;
  @Input('type') btnType: ButtonTypes;
  @Input() color?: ButtonColor;
  @Input() size?: ButtonSize;
  ...
}

【问题讨论】:

  • 自定义属性disabled@Input()ButtonComponent 中看起来像什么?
  • 您是否也知道 add/save/cancel 不是标准 HTML &lt;button&gt; 元素的类型? HTML <button> type Attribute。有效类型为“button”、“submit”和“reset”。
  • 更新为包含按钮@Inputs
  • 这些答案对您有帮助吗?

标签: angular typescript


【解决方案1】:

您可以使用@HostBinding('class'):host-selectors 根据您的shouldBeDisabled 属性禁用通过pointer-events: none 进行的点击:

//foo.component.scss

:host(.disabled) {
  // Disable click event.
  pointer-events: none;
}

:host(.enabled) {
  // No customizations.
}

//foo.component.html
...
<my-button
  (click)="saveWidget()"
  [disabled]="shouldBeDisabled"
  type="{{buttonTypes.save}}">
</myButton>
...

//foo.component.ts
import { ButtonTypes } from './myButton';

export class FooComponent implements OnInit {

  @HostBinding('class')
  get hostClass(): string {
    return this.shouldBeDisabled ? 'disabled' : 'enabled';
  }

  get shouldBeDisabled() {
    return true; //Normally a real test in here
  }
  ...
}

我发现Learning Angular: Conditionally add styles to an element 对于解决类似问题非常有用。

【讨论】:

  • 是的,这是最简单的方法! :)
  • 完美,谢谢!并且很抱歉迟到接受这个:)
【解决方案2】:

ButtonComponent 的内部disabled 状态不会阻止附加到组件的外部(click) 触发。但是,您可以根据@Input disabled: boolean 防止(click)ButtonComponent 中发生。将此与@Output() 结合使用可以让您在父级中侦听启用子级的按钮单击事件。这与 Angular 文档中的 Parent listens for child event 相同。

此解决方案有效地仅添加了几行额外的代码,并有助于确保除非启用并单击按钮,否则不会执行外部处理程序。

按钮组件:

import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-button',
  template: `
    <button [type]="type" [disabled]="disabled" (click)="handleClick()">
      <ng-content></ng-content>
    </button>
  `
})
export class ButtonComponent  {
  @Input() disabled: boolean;
  @Input() type: string;
  @Output() clicked = new EventEmitter<boolean>();

  // will not execute if the button is disabled
  handleClick() {
    console.log('ButtonComponent: clicked');
    this.clicked.emit(true);
  }
}

父组件:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <app-button
        [disabled]="shouldBeDisabled"
        [type]="'button'"
        (clicked)="saveWidget($event)">ENABLED</app-button>
    <app-button
        [disabled]="shouldBeDisabled"
        [type]="'button'"
        (clicked)="saveWidget($event)">DISABLED</app-button>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  get shouldBeDisabled() { return true; }
  get shouldNotBeDisabled() { return false; }

  saveWidget(emittedValue: boolean) {
    console.log(emittedValue);
    console.log('saveWidget()');
  }
}

您可以将所需的任何内容传递给父母。在此示例中,它是 boolean,但它可能有助于识别小部件或您在示例中需要的任何内容。

这是一个 StackBlitz 演示实际功能。

【讨论】:

  • 是哪个位导致按钮点击不被注册?努力应用此修复程序,因为我的按钮仍会触发 click 方法。编辑:一旦我将@Output() 发射器的名称从点击更改为点击
  • 一个实际的
【解决方案3】:

您的按钮组件实际上是什么样的?即它是否收到disabled 道具?

在这种情况下,给它添加一个(click) 事件,如果它被禁用就中断。

例如

clickHandler() {
   if(this.disabled) {
      return;
   } else {
      // do something...
   }
}

模板

<your-button (click)="clickHandler()">button</your-button>

如果做不到这一点,请使用 ngClass 应用禁用的 CSS 类,然后使用:

pointer-events: none;

【讨论】:

    猜你喜欢
    • 2018-07-08
    • 1970-01-01
    • 2013-11-02
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 2013-05-18
    • 1970-01-01
    相关资源
    最近更新 更多