如何在Angular 7中从子组件传递到父属性指令?

时间:2019-07-18 17:01:00

标签: javascript angular typescript ckeditor

我的目标是让自定义指令在其作用域内侦听DOM事件;并处理该事件。在这种情况下,该DOMEvent将发生在我无法控制的第三方组件中。

在Angular中,我在组件中定义了以下模板。

此模板的指令(称为my-directive)已与ckeditor组件的keypress事件挂钩。

我不拥有ckeditor的代码;并且试图摆脱不必更改任何代码的麻烦,以便使它成为可重用的钩子。

somecomponent.ts

<!-- lots of irrelevant template code snipped -->
<my-directive>
  <ckeditor [editor]="Editor" (keypress)="pressed($event)"></ckeditor>
</my-directive>
<!-- lots of irrelevant template code snipped -->

my.directive.ts定义如下:

import { Directive, OnInit } from "@angular/core";

@Directive({
    selector: 'my-directive',
  })
  export class MyDirective implements OnInit {
    public pressed(e: Event) : void {
        console.table(e);
    }

    constructor(
    ) { }
    ngOnInit() : void {
    }
}

并且CKEditor来自angular-ckeditor软件包;并使用以下导入:

import { CKEditorModule } from '@ckeditor/ckeditor5-angular'; import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';

当我尝试从ckeditor标记调用pressed函数时;它抱怨pressed不是一个函数:

exception-handler.ts:41 TypeError: _co.pressed is not a function
    at Object.eval [as handleEvent] (SomeComponent.html:60)
    at handleEvent (core.js:21673)
    at callWithDebugContext (core.js:22767)
    at Object.debugHandleEvent [as handleEvent] (core.js:22470)
    at dispatchEvent (core.js:19122)
    at core.js:19569
    at HTMLUnknownElement.<anonymous> (platform-browser.js:993)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:16147)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422) "/myurl/1"

也许问题在于Angular正在尝试在pressed()上调用ckeditor

所以我尝试使用模板引用变量:

<!-- lots of irrelevant template code snipped -->
<my-directive #md>
  <ckeditor [editor]="Editor" (keypress)="md.pressed($event)"></ckeditor>
</my-directive>
<!-- lots of irrelevant template code snipped -->

所以我得到了这个错误:

TypeError: jit_nodeValue_4(...).pressed is not a function
    at Object.eval [as handleEvent] (SomeComponent.html:60)
    at handleEvent (core.js:21673)
    at callWithDebugContext (core.js:22767)
    at Object.debugHandleEvent [as handleEvent] (core.js:22470)
    at dispatchEvent (core.js:19122)
    at core.js:19569
    at HTMLUnknownElement.<anonymous> (platform-browser.js:993)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:16147)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422) "/myurl/1"

最重要的是,我的问题是这样:

如何允许指令响应子组件中引发的标准DOM事件?

我不想修改子组件;在某些情况下,我做不到(这不是我的代码)。我希望可以将该指令添加到其他组件的模板中,而不必在内部进行修改以允许该指令实现新的行为。

1 个答案:

答案 0 :(得分:0)

经过更多调查;似乎通过附加到子组件的模板声明来侦听标准DOM事件是过大的,并且我可以通过执行以下操作来实现所需的目标:

  1. @HostListener添加到MyDirective
import { Directive, OnInit } from "@angular/core";

@Directive({
    selector: 'my-directive',
  })
  export class MyDirective implements OnInit {
    public pressed(e: Event) : void {

    }
    @HostListener('keypress') onKeyPress(e: Event) {
        console.table(e);
    }
    constructor(
    ) { }
    ngOnInit() : void {
    }
}
  1. 修改模板以删除声明,并仅将my-directive声明保留在子代中:
<!-- lots of irrelevant template code snipped -->
<my-directive>
  <ckeditor [editor]="Editor"></ckeditor>
</my-directive>
<!-- lots of irrelevant template code snipped -->

现在,如果在my-directive标签(无论是其子元素还是子标签)中发生了任何按键事件,它将引发一个事件,@HostListener将对此做出响应。