Reputation: 972
Let's say we have a lot of method's where we want to add a confirmation dialog to the original method. Therefor we decide to build a custom decorator.
@Component({...})
export class HeroComponent {
constructor(private dialog: MatDialog) {}
@confirmByDialog(this.dialog)
deleteHero() { ... }
}
export function confirmByDialog (dialog: MatDialog): MethodDecorator {
return (target: Function, key: string, descriptor: any) => {
const originalMethod = descriptor.value;
descriptor.value = (...args: any[]) => {
const dialogRef = dialog.open(ConfirmationDialogComponent);
return dialogRef
.afterClosed()
.subscribe((confirmed: boolean) => {
if (confirmed) {
originalMethod();
}
});
};
return descriptor;
};
}
But that approach does not work because of
Cannot read property 'dialog' of undefined (hero.component.ts)
How to pass additional parameters to a decorator? I already thought about passing the dialog
to the original function itself to access it via the args
, but that sounds like a really dirty hack to me?
Thanks in advance!
Upvotes: 2
Views: 3651
Reputation: 249486
You can't access instance fields in the decorator parameters. The decorator is applied for the class not for an instance.
The simple solution is to pass in the name of the dialog field but that means the field need to be public.
You also need to change how you forward the parameters and this
. Since we need access to the actual passed in this we can't use an arrow function and we need to use apply
to forward this
class HeroComponent {
constructor(public dialog: MatDialog) { }
@confirmByDialog("dialog") // Checked by the compiler.
deleteHero() { }
}
function confirmByDialog<K extends string>(dialog: K) {
return (target: Record<K, MatDialog>, key: string, descriptor: any) => {
const originalMethod: Function = descriptor.value;
descriptor.value = function (this: Record<K, MatDialog>, ...args: any[]) {
const dialogRef = this[dialog].open(ConfirmationDialogComponent);
return dialogRef
.afterClosed()
.subscribe((confirmed: boolean) => {
if (confirmed) {
originalMethod.apply(this, ...args);
}
});
};
return descriptor;
};
}
Upvotes: 4