如何将组件方法绑定到 Angular 之外的按钮 'onclick'?
How to bind component method to button's 'onclick' outside Angular?
我有一个 Angular 4 应用程序和一个组件,它们动态生成一些标记。我需要将此组件的方法绑定到此标记中的某个元素。
我发现的唯一方法是使用 onclick
属性生成此元素。所以现在我的组件的构造函数看起来像这样:
constructor(private _zone: NgZone) {
window['Component'] = {
myMethod: this.myMethod.bind(this),
zone: _zone
}
}
...我生成的标记看起来像这样:
<button onclick="window.Component.myMethod()">I was generated dynamically after Angular compilation, so you can't use '(click)="method(params)"' on me! Haha!</button>
而且有效!几乎...单击按钮后,我需要触发 window
上的某些事件(例如焦点或模糊),然后我的方法才会运行。请任何人帮助。
看起来问题是当我 运行 在 Angular 区域之外的方法时,UI 没有刷新。所以我这样做了:
(<any>window).myMethod = (params) => this._zone.run(
() => {
this.myMethod(params);
});
不知道这个解决方案有多好,但它工作正常。
UPD: 糟糕,不好。方法没有运行我第一次点击按钮,之后一切正常。
你必须使用:this.zone.runOutsideAngular
我附上了示例来说明 angular 按钮和组件内部事件绑定的位置。如我的示例所示,不要忘记取消绑定 onDestroy 事件。
this.zone.runOutsideAngular(() => {
document.querySelector('#btn').addEventListener('click', () => {
this.foo();
});
});
https://stackblitz.com/edit/angular-xtkw3z?file=app%2Fapp.component.ts
更新 1:
我已经创建了自定义指令,专门用于在您的按钮上绑定点击事件。
我已经删除了 DOMSanitizer,因为我们会自动添加 Event.stopPropagation()。所以你必须自己控制字符串是否安全。
@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'));
});
});
});
}
}
源代码在这里:
https://stackblitz.com/edit/angular-cua3is?file=app/app.component.ts
我有一个 Angular 4 应用程序和一个组件,它们动态生成一些标记。我需要将此组件的方法绑定到此标记中的某个元素。
我发现的唯一方法是使用 onclick
属性生成此元素。所以现在我的组件的构造函数看起来像这样:
constructor(private _zone: NgZone) {
window['Component'] = {
myMethod: this.myMethod.bind(this),
zone: _zone
}
}
...我生成的标记看起来像这样:
<button onclick="window.Component.myMethod()">I was generated dynamically after Angular compilation, so you can't use '(click)="method(params)"' on me! Haha!</button>
而且有效!几乎...单击按钮后,我需要触发 window
上的某些事件(例如焦点或模糊),然后我的方法才会运行。请任何人帮助。
看起来问题是当我 运行 在 Angular 区域之外的方法时,UI 没有刷新。所以我这样做了:
(<any>window).myMethod = (params) => this._zone.run(
() => {
this.myMethod(params);
});
不知道这个解决方案有多好,但它工作正常。
UPD: 糟糕,不好。方法没有运行我第一次点击按钮,之后一切正常。
你必须使用:this.zone.runOutsideAngular
我附上了示例来说明 angular 按钮和组件内部事件绑定的位置。如我的示例所示,不要忘记取消绑定 onDestroy 事件。
this.zone.runOutsideAngular(() => {
document.querySelector('#btn').addEventListener('click', () => {
this.foo();
});
});
https://stackblitz.com/edit/angular-xtkw3z?file=app%2Fapp.component.ts
更新 1:
我已经创建了自定义指令,专门用于在您的按钮上绑定点击事件。
我已经删除了 DOMSanitizer,因为我们会自动添加 Event.stopPropagation()。所以你必须自己控制字符串是否安全。
@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'));
});
});
});
}
}
源代码在这里: https://stackblitz.com/edit/angular-cua3is?file=app/app.component.ts