I have an Angular 4 app and a component, which generate some markup dynamically. And I need to bind this component's method to some element in this markup.
The only way, that I found is to generate this element with onclick
attribute. And so now my component's constructor looks like that:
constructor(private _zone: NgZone) {
window['Component'] = {
myMethod: this.myMethod.bind(this),
zone: _zone
}
}
...and the peice of my generated markup looks like that:
<button onclick="window.Component.myMethod()">I was generated dynamically after Angular compilation, so you can't use '(click)="method(params)"' on me! Haha!</button>
And it works! Almost... After clickin the button I need some event on window
to be fired (e.g. focus or blur), only then my method runs. Please, anybody, help.
you have to use : this.zone.runOutsideAngular
i have attach sample to illustrate where you have button out of angular and event Binding inside component. As illustrate on my sample, don't forget to unbind your event onDestroy.
this.zone.runOutsideAngular(() => {
document.querySelector('#btn').addEventListener('click', () => {
this.foo();
});
});
https://stackblitz.com/edit/angular-xtkw3z?file=app%2Fapp.component.ts
update 1:
I have create custom directive dedicated to bind click event on your button.
I have remove DOMSanitizer because we add Event.stopPropagation() automatically. So you have to do your own control if string is safe or not.
@Directive({
selector: '[profil]'
})
export class UserProfilDirective implements OnInit, AfterViewInit {
@Input('profil') html: string;
constructor(
private el: ElementRef,
private zone: NgZone,
private renderer: Renderer2
) {
}
ngOnInit() {
//Take your html and add it as child html if current directive instance.
this.el.nativeElement.innerHTML = this.html;
}
ngAfterViewInit() {
//Out of angular.
this.zone.runOutsideAngular(() => {
// For each .profil of current instance.
[].forEach.call(this.el.nativeElement.querySelectorAll('.profil'), (el:Element, index: number) => {
//Ask rendering to add onClick event.
this.renderer.listen(el, 'click', (e) => {
//Do what ever you want with data profil such as output Event
console.log(e.srcElement.getAttribute('data-profile'));
});
});
});
}
}
Source code here : https://stackblitz.com/edit/angular-cua3is?file=app/app.component.ts