6

In my application I have a button with a click even on it:

<button class="btn btn-default" (click)="doSomething()">

From within the doSomething method, is there any way to remove the (click) event from the button (so the user can't trigger the functionnality anymore?).

I tried to set a disabled prop on the button but it doesn't change Angular2 behavior.

I tryed to use (click)="doSomething($event) and then

doSomething($event) {
  // My method logic goes here
  ...
  ...
  console.log('Method Logic');

  //Attempt to overwrite click event
  let target = event.target || event.srcElement || event.currentTarget;
  this.renderer.listen(target, 'click', (event) => {
      console.log('clic block');
    });
}

But It doesn't "replace" the click event. So after that, on click, both original logic and the "click block" console log are triggered!

1
  • What exactly do you want to do if you can't unclick the event? Commented Jan 2, 2017 at 23:31

3 Answers 3

6

Method 1:

You can set a boolean variable, so if the user calls the function, boolean value changes and the user will be able to call the function on click again but actually nothing will happen.

bool: boolean = true;

doSomething($event) {
  if (this.bool) {
    // My method logic goes here
    ...
    ...
    console.log('Method Logic');
    this.bool = false;
  }
}

Method 2:

You can add a condition to your html component, if specified variable (in this case bool) is true, the function is going to be executed, but only once because the bool variable will be set to false and the click function will execute nothing (null) from now on.

bool: boolean = true;

doSomething($event) {
  // My method logic goes here
  ...
  ...
  console.log('Method Logic');
  this.bool = false;
}

(click)="bool ? doSomething($event) : null"

Sign up to request clarification or add additional context in comments.

3 Comments

I like guard clauses: if(!this.bool) return; ... looks cleaner.
@SparK Same here, but I just wanted to clarify the code as much as it possible.
It was so simple I didn't think about it! Thanks. I like guard too.
5

The downside of just adding a guard variable for the execution is that the actual event listener is still in place and will trigger Angular's change detection when clicked, even though it doesn't do anything.

To actually remove the event listener, you have to add it via the component's Renderer. This will return a function that removes the event listener when called:

import {Component, AfterViewInit, Renderer, ViewChild, ElementRef} from '@angular/core';

@Component({
  template: `<button #button>...</button>`
})
export class SampleComponent implements AfterViewInit {

  @ViewChild('button') button: ElementRef;
  private cancelClick: Function;

  constructor(private renderer: Renderer) {}

  ngAfterViewInit() {
    this.cancelClick = this.renderer.listen(this.button.nativeElement, 'click',
      ($event: any) => this.handleClick($event));
  }

  handleClick($event: any) {
    this.cancelClick();
    // ...
  }
}

If your goal is to just remove the event listener when the event is fired for the first time, this can be implemented as a plugin to Angular's event system. I added it as a part of my ng2-events utility library [source], which lets you now do the following:

<button (once.click)="handleClick($event)">...</button>

3 Comments

I get your point on not removing the event itself. That I don't get is how the listen method in your code example is actually removing the event. It just redirects to handleClick which is the called method anyway no?
The Renderer.listen() method returns a function. That function removes the event listener when called (Angular source). We assign that returned function to this.cancelClick. When we call that, the event listener is removed and this.handleClick() is never called again.
+1. I used this technique for an array of children elements using @ViewChildren() and by storing the functions returned by Renderer.listen() in an array.
3

For people dealing with Observable / Subject for handling some events :

<button (click)="clickEvents$.next($event)">
class MyComponent {
  clickEvents$ = new Subject<MouseEvent>();
  firstClick$ = this.clickEvents.take(1); // Observable of first click
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.