Angular : onClick on html element according to its class

10,413

Solution 1

Normally the 3rd party widget should provide a click handler like so:

<myWidGet (click)="myFunction($event)"></myWidGet>

and in the controller:

myFunction(evt) {
  const target = evt.target
  console.log('test')
}

However, if they do not expose click handlers then I would seriously consider not using the widget.

If want to use the widget anyway then do this using jQuery:

ngAfterViewInit() {
  $('.dx-edit-row.dx-command-edit.dx-link-save').on('click', (evt) => {
    const target = evt.target
    console.log('test')
  });
}

The above assumes ALL these classes are present on the same button.

Or just use vanilla JS.

If the buttons are not available on ngAfterViewInit() then you could do this:

ngAfterViewInit() {
  const interval = setInterval(() => {
    const button = $('.dx-edit-row.dx-command-edit.dx-link-save')
    // if button is ready
    if (button) {
      // add click handlers
      button.on('click', (evt) => {
        const target = evt.target
        console.log('test')
      });
      // stop polling
      clearInterval(interval)
    }
  }, 100)
}

Solution 2

Accessing DOM elements using jQuery is not really a good practice. Use ElementRef with Renderer2 instead. Also, there's nothing like ngOnViewInit in Angular. It's ngAfterViewInit.

Once the View loads, inside the ngAfterViewInit, you can get access to the HTMLElement using the nativeElement on ElementRef instance. You should explicitly typecast it into HTMLElement so as to get intellisence.

You can then call querySelector on it and pass it the classes. This will give you the button element.

Now you use Renderer2's instances' listen method. This takes three args:

  1. The element you want to listen to events on(btnElement).
  2. The Name of the event(click).
  3. The callback function.

This would translate to code like:

constructor(
  private el: ElementRef,
  private renderer: Renderer2
) {}

ngAfterViewInit() {
  const btnElement = (<HTMLElement>this.el.nativeElement)
    .querySelector('.dx-edit-row.dx-command-edit.dx-link-save');

  this.renderer.listen(btnElement, 'click', () => {
    alert('Buton was clicked');
  });
}

Here's a Working StackBlitz for your ref.

Share:
10,413

Related videos on Youtube

firasKoubaa
Author by

firasKoubaa

Updated on June 04, 2022

Comments

  • firasKoubaa
    firasKoubaa almost 2 years

    Under my Angular App, I'm using some 3rd library widget which is rendering in my component.

    My template is:

    <div>
      <myWidGet></myWidGet>
    </div>
    

    Inside myWidGet there some button element that I want handle their events. The button have those classes : .dx-edit-row .dx-command-edit .dx-link-save

    so i i do that :

    export class myClass AfterViewInit { 
    
      constructor(private elRef: ElementRef){}
    
      ngAfterViewInit() {
        this.elRef.nativeElement.querySelector('.dx-edit-row .dx-command-edit .dx- 
    link-save').on('click', (e) => {
          alert('test');
        });
      }
    
    }
    

    My purpose is to get reference to my button and handle the click event from it.

    Suggestions?

    • Talg123
      Talg123 over 5 years
      I think Im abit confused. why would you use native JS queryselector inside angular? you cant get any interaction with those buttons?
    • miselking
      miselking over 5 years
      Maybe get myWidGet with ViewChild and try getting button with querySelector. Although, this way of doing things is not "Angular" way, that button should emit an Output event...
    • ConnorsFan
      ConnorsFan over 5 years
      You could set a click event handler on the div and check the classes of the event.target to determine if the widget button was clicked (assuming that the click event propagation was not stopped).
    • ConnorsFan
      ConnorsFan over 5 years
      See this stackblitz for an example of event delegation, as suggested in my previous comment.
  • firasKoubaa
    firasKoubaa over 5 years
    i ve tried to do it with jquery : the problem that , this button appears after a while (it s a table where i should open some dropdowns to see the button) , so i can t get the console.log working
  • danday74
    danday74 over 5 years
    ok then if the buttons are not available in ngOnViewInit() you will have to poll, i'll add an example to my answer - this code will keep firing until the buttons are ready and then add the click handler and then stop firing, this is not great but this is what happens if you do not use professional 3rd party libs
  • firasKoubaa
    firasKoubaa over 5 years
    i'm using devextereme-angular of DevExpress and for some widget (datagrid) , there is a lack for an edit event
  • danday74
    danday74 over 5 years
    heres the link for that lib, actually we use it at work and it is a good lib - js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/…
  • danday74
    danday74 over 5 years
    I've never done editing with it but I believe the data is two way bound, so when you make changes to the datagrid data in the controller the data in the datagrid updates and vice versa, maybe your controller data is updating and thus you do not need to handle the edit event?
  • firasKoubaa
    firasKoubaa over 5 years
    when you use a datagrid with columns which all refers to cellTemplates , the event "onUpdating" of the datagrid would not detect the changes and will not fire , and there is no way to trigger it ( i need it to send data to WS)
  • danday74
    danday74 over 5 years
    are the buttons in the cellTemplates? prob not but if so add (click) to the buttons there - if not polling may be the only solution - all the best
  • Christian Vincenzo Traina
    Christian Vincenzo Traina over 5 years
    `ElementRef' isn't a so better practice
  • danday74
    danday74 over 5 years
    sorry it is ngAfterViewInit my apologies
  • SiddAjmera
    SiddAjmera over 5 years
    @CristianTraìna, do you have any mention of that somewhere? I'd like to know more about it. I just feel it's better than polluting your Angular code with jQuery.
  • firasKoubaa
    firasKoubaa over 5 years
    @SiddAjmera how to do , if my buttonons are not appeared afterViewInit (i would open a dropdown to see the button) ? .. of course without refereing to the click of dropdown opening
  • SiddAjmera
    SiddAjmera over 5 years
    You mean your buttons are not present in the DOM on View Load?
  • firasKoubaa
    firasKoubaa over 5 years
    that amazing , but it lack something : my button didn appear onInti of the widegt (it appears after some dropodown opening inside the same widget , how to do it ?
  • firasKoubaa
    firasKoubaa over 5 years
    ERROR TypeError: Cannot read property '__zone_symbol__addEventListener' of null
  • Suresh Kumar Ariya
    Suresh Kumar Ariya over 5 years
    You can handle this using *ngIf. Set the boolean to true based on ur condition.
  • firasKoubaa
    firasKoubaa over 5 years
    u ven got the ideaa . The button inside the widget is not show since the init of the widget , so that i ve got the last error message . How may i initialize the vent listener when the button appears
  • Suresh Kumar Ariya
    Suresh Kumar Ariya over 5 years
    i moved those logic to 'AfterViewInit' life cycle hook
  • SiddAjmera
    SiddAjmera over 5 years
    Directives don't have AfterViewInit lifecycle hook. They don't have any hook related to Content or View as they don't have a content or view.
  • Christian Vincenzo Traina
    Christian Vincenzo Traina over 5 years
    @SiddAjmera you shouldn't just query an element inside a method. Direct access to DOM, in angular, is considered a bad practice. It's better if you just use the default (click) event handler, the angular way