2

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?

4
  • 1
    I think Im abit confused. why would you use native JS queryselector inside angular? you cant get any interaction with those buttons? Commented Oct 6, 2018 at 16:22
  • 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... Commented Oct 6, 2018 at 16:37
  • 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). Commented Oct 6, 2018 at 17:06
  • See this stackblitz for an example of event delegation, as suggested in my previous comment. Commented Oct 6, 2018 at 17:18

3 Answers 3

3

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)
}
Sign up to request clarification or add additional context in comments.

8 Comments

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
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
i'm using devextereme-angular of DevExpress and for some widget (datagrid) , there is a lack for an edit event
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/…
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?
|
3

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.

5 Comments

`ElementRef' isn't a so better practice
@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.
@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
You mean your buttons are not present in the DOM on View Load?
@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
0

You can customize the third party widget using Angular Directive. It will allow to access DOM element and attach listeners using renderer2.

<myWidGet customEvents></myWidGet>

Directive:

@Directive({
   selector: '[customEvents]'
})
export class CustomEventsDirective implements OnInit {
    private element: any;
    constructor(private el: ElementRef, private renderer: Renderer2) {
        this.element = el.nativeElement;
    }
    ngOnInit() {

       const btnElement = this.element.querySelector('.dx-edit-row.dx-command-edit.dx-link-save');

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

6 Comments

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 ?
ERROR TypeError: Cannot read property '__zone_symbol__addEventListener' of null
You can handle this using *ngIf. Set the boolean to true based on ur condition.
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
i moved those logic to 'AfterViewInit' life cycle hook
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.