【问题标题】:Angular component: disable click eventAngular 组件:禁用点击事件
【发布时间】:2019-08-19 12:09:47
【问题描述】:

我正在创建一个像这样的可重用组件:

<my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>

我想在属性 isDisabled 为 true 时禁用点击事件,我尝试过类似的方法,但它不起作用。

packages/component/my-button.component.html

<button  [disabled]="isDisabled" #myButton>
        <ng-content></ng-content>
</button>

packages/component/my-button.component.ts

@ViewChild('uxButton') uxButton: ElementRef;
@Input() isDisabled: boolean = false;

this.myButton.nativeElement.parentNode.removeEventListener('click' , (e) => {
       e.stopPropagation();
});

【问题讨论】:

    标签: angular angular-components


    【解决方案1】:

    这可以通过使用布尔变量来检查某些条件是否为真,如下所示:

    <my-button (click)="is_some_condition_true ? null : click($event)"> submit </my-button>
    

    这种情况可能是例如:

    将组件中的editMode、addMode或isDisabled等变量的初始值设置为false,然后在按钮实际禁用时将其设置为true。

    参考:how-to-disabled-click-event-or-any-event-if-condition-is-false-true-in-angular

    【讨论】:

      【解决方案2】:

      我能够禁用 scss 中禁用按钮的单击事件。这是我添加的

      :host {
      button {
      &:disabled:active {
            pointer-events: none;
      }
      }
      }
      

      【讨论】:

      • 您应该删除此评论,因为它与 Angular 无关。如果你不删除这个随机的仇恨者会否决...
      【解决方案3】:

      如果您想保留旧版点击事件而不使用输出。 有一个基于前面几个的组合解决方案。

      my-button.component.html

      <button [disabled]="disabled">
        <ng-content></ng-content>
      </button>
      

      my-button.component.ts

      export class MyButtonComponent {
        @HostBinding('style.pointer-events') get pEvents(): string {
          if (this.disabled) {
            return 'none';
          }
          return 'auto';
        }
      
        @Input()
        disabled: boolean = false;
      
       constructor() {}
      }
      

      父组件,您将在其中调用您的组件,例如app.component.html

      <my-button [disabled]="isDisabled" (click)="onClickFnc()">
        <span>Save which not trigger click when button is disabled</span>
      </my-button>
      

      【讨论】:

        【解决方案4】:

        首先,我们需要问自己为什么要创建一种新型的按钮组件,而我们已经有了一个原生的按钮组件。可能是这样的:

        • 利用一些 Angular 助手,例如动画
        • 在执行某些点击处理程序期间禁用按钮。
        • 进度指示。
        • ...

        如果可以使用 本机按钮(解决方案 0)解决要求,请坚持下去。否则,继续。

        在创建可重用文件之前,我们需要了解两件重要的事情 按钮组件:

        K1 只能禁用有限的 HTML 元素子集, https://html.spec.whatwg.org/multipage/semantics-other.html#disabled-elements。这 表示即使元素被禁用也会触发点击处理程序。

        K2 在 Angular 中,无法从内部控制外部事件 里面。 https://github.com/angular/angular/issues/12630

        解决方案 1. 点击处理程序作为输入

        要解决 K2,您可以使用 @Input 回调而不是 事件绑定。然后你可以从内部控制它,并且 您甚至可以访问内部回调的结果。它 看起来像:

        <my-button [myClick]="doIt"> or with arguments <my-button [myClick]="doIt.bind(1)">
        
        @HostListener('click') onClick(event) {
          this.myClick();
        }
        

        既然你可以完全控制回调,你可以省略调用 当它是disabled 时。

        需要此解决方案的一个问题是带有进度指示的按钮。当您完全控制回调时,库按钮可以开始/停止进度条的动画,甚至可以通过在进行中禁用它来阻止其他点击。将其与本模块中的进度按钮进行比较 https://github.com/michaeldoye/mat-progress-buttons 你需要的地方 每个按钮实例的启动/停止动画!

        缺点:非标准外观。您的图书馆用户会喜欢为什么会这样 回调输入而不是事件绑定...

        解决方案 2. CSS

        您可以尝试使用 CSS pointer-events:none 解决 K1。它 可以在表面上工作,阻止用户鼠标触发的点击 事件。但是,您仍然可以务实地单击 按钮。 myButton.click() 在按钮被“禁用”时仍会触发。

        缺点:“已禁用”元素仍为 clickable。可能,不适合 您的图书馆用户正在编写自动化测试。

        解决方案 3. 组件化原生按钮

        要使禁用和事件按预期工作,您需要应用 组件直接放在 HTML 按钮元素上。在 Angular Material 中,它看起来 喜欢&lt;button mat-button&gt;https://github.com/angular/components/blob/master/src/material/button/button.ts#L66

        而且很简单:

        @Component({
          selector: 'button[my-button]',
          template: '<ng-content></ng-content>'
        })
        

        并使用它:

        <button my-button (click)="doIt()" [disabled]="isDisabled">Save</button>
        

        现在当my-button 被禁用时不会触发点击事件。

        缺点:必须有原生按钮,my-button 看起来更像 是一个指令而不是一个组件。

        结论

        我建议使用最符合要求的解决方案,而不是 CSS hack 解决方案。

        【讨论】:

          【解决方案5】:

          下面的CSS也解决了:

          # This prevents host to get a direct click
          :host {
            pointer-events: none;
          }
          
          # This prevents the span inside the button to "steal" the click from the button
          :host /deep/ button span {
            pointer-events: none;
          }
          
          # Now only the button can get a click 
          # Button is the only smart enough to stop propagation when needed
          button {
            pointer-events: auto;
          }
          

          现在您不必像其他答案那样手动传递点击事件:您有旧的(点击)事件:D

          <my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
          

          在您的自定义组件中,您只需传递 disabled 属性:

          <button  [disabled]="isDisabled" #myButton>
                  <ng-content></ng-content>
          </button>
          

          还要考虑从another stackoverflow answer 修改的stackblitz

          【讨论】:

          • 请注意 css pointer-events: none 将禁用其他鼠标事件。反过来,工具提示之类的东西将不再起作用,因为没有触发鼠标事件。
          【解决方案6】:

          这样试试

          <button  [disabled]="isDisabled" (click)="btnClick.emit($event)">
                  <ng-content></ng-content>
          </button>
          
          @Input() isDisabled: boolean = false;
          @Output() btnClick = new EventEmitter();
          

          使用Output 并且默认情况下,如果按钮被禁用,按钮单击事件将不起作用。好好利用吧

          <my-button [isDisabled]="isDisabled" (btnClick)="click($event)"> submit </my-button>
          

          【讨论】:

          • 我想在可重用的组件中做这件事
          • 我喜欢你的想法,但它不起作用,我在你的代码中看不到任何@output
          • 对不起,我犯了一个错误。更新了答案。 btnClick 是一个输出
          【解决方案7】:

          你可以在(click)属性上查看:

          <my-button [isDisabled]="isDisabled" (click)="!isDisabled && click($event)"> submit </my-button>
          

          【讨论】:

          • 这是最简单的解决方案,我从来不知道它是这样工作的。谢谢!
          • 这不是一个好的答案。如果您在 100 个不同的地方使用您的按钮,那么这就是 100 次额外检查。
          【解决方案8】:

          您应该使用documentation 中提到的[disabled] 属性:

          <button [disabled]="isDisabled" (click)="disableButton()">Disable button</button>
          

          然后在你的代码中

          export class AppComponent  {
            isDisabled = false;
          
            disableButton() {
              this.isDisabled = true;
              // your code...
            }
          }
          

          查看StackBlitz 以获取演示。

          【讨论】:

          • 我想在可重复使用的组件中做它
          【解决方案9】:

          我认为问题出在您的代码中:

          <my-button [isDisabled]="isDisabled" (click)="click($event)"> submit </my-button>
          

          应该是

          <my-button [disabled]="isDisabled" (click)="click($event)"> submit </my-button>
          

          【讨论】:

          • isDisabled 是可重用组件的输入属性
          【解决方案10】:

          我们可以使用 ElementRef/HostListener 根据需要添加事件侦听器/删除,但简单的修复方法如下。

          click(event) {
          if (this.isDisabled) {
          return;
          }
          ......
          }
          

          【讨论】:

          • 我必须在可重用组件内完成,我使用了 ElementRef 但不起作用
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-11-11
          • 2017-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-18
          • 1970-01-01
          相关资源
          最近更新 更多