You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在ngx-summernote中插入Angular自定义元素:Input传值与Output事件绑定异常求助

问题描述

我一直使用ngx-summernote作为富文本编辑器,因项目需求需向其中动态插入自定义Angular组件。发现编辑器支持动态HTML插入但无法识别Angular组件,遂将组件转为Angular自定义元素,成功插入编辑器。但目前遇到两个问题:

  • 向自定义元素的@Input()传递对象时,组件接收值为undefined;
  • @Output()事件okClicked无法触发绑定的testSpecOkClicked方法。

相关代码片段

ngx-summernote的HTML配置

<div
    [ngxSummernote]="summernoteOptions"
    [ngxSummernoteDisabled]="domain.screenIsViewOnly"
    [ngxSummernoteView]="specificInstructionRecord.specificInstruction"
    [(summernoteModel)]="specificInstructionRecord.specificInstruction"
></div>

自定义测试Angular组件

import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
import lodash from 'lodash';

@Component({
    selector: "spec-inst-test-component",
    templateUrl: "./specInstTestComponent.html"
})
export class SpecInstTestComponent implements OnInit {
    @Input() input: any;
    @Output() okClicked = new EventEmitter<any>();

    valueObject : {
        textVal: string,
        numberVal: number
    }

    textVal: string;
    numberVal: number;

    constructor() {
        
    }

    ngOnInit() {
        if(!lodash.isEmpty() && (typeof this.input) == "string") {
            this.input = JSON.parse(this.input);
        }
    }

    testButtonClicked() {
        this.valueObject = {
            textVal : this.textVal,
            numberVal: this.numberVal
        }
        this.okClicked.emit(this.valueObject);
    }
}

自定义组件的模板HTML

<div>
    <div *ngIf="input.type == 'input'">
        <label>{{input.label}}</label>
        <input type="text" [(ngModel)]="textVal"/>
    </div>
    <div *ngIf="input.type == 'number'">
        <label>{{input.label}}</label>
        <input type="number" [(ngModel)]="numberVal"/>
    </div>
    <button (click)="testButtonClicked()">OK</button>
</div>

将自定义组件转为自定义元素的过程

export class AppNgModule {

  constructor(private injector: Injector) {
      const specInstTestCustomElement = createCustomElement(SpecInstTestComponent, {injector: this.injector});
      if(!customElements.get("spec-inst-test-element")) {
          customElements.define("spec-inst-test-element", specInstTestCustomElement);
      }
  }
}

向summernote动态插入自定义元素的代码

addSpecInstTestEl() {
        this.inputObj = {
            type: "input",
            lable: "text field",
        }
        let html = `<spec-inst-test-element [input]="inputObj" (okClicked)="testSpecOkClicked($event)"></spec-inst-test-element>`
        this.specificInstructionRecord.specificInstruction = this.specificInstructionRecord.specificInstruction + html;
    }

问题原因及解决方案

这些问题并非ngx-summernote导致,而是自定义元素与Angular组件的绑定机制存在差异,且插入的HTML不在Angular的模板编译上下文范围内,需要按照原生自定义元素的规则处理:

1. 解决@Input()传递对象为undefined的问题

  • 自定义元素不支持Angular的[input]属性绑定语法,且对象类型的属性必须以JSON字符串形式传递(原生自定义元素只能接收字符串类型的属性值)。
  • 修正addSpecInstTestEl方法,将对象转为JSON字符串后通过原生属性传递:
addSpecInstTestEl() {
    this.inputObj = {
        type: "input",
        label: "text field", // 修正拼写错误:lable → label
    };
    // 将对象转为JSON字符串,用原生属性传递
    const html = `<spec-inst-test-element input='${JSON.stringify(this.inputObj)}'></spec-inst-test-element>`;
    this.specificInstructionRecord.specificInstruction += html;
}
  • 修正组件ngOnInit中的lodash调用错误(原代码未传入参数):
ngOnInit() {
    // 修正:判断this.input是否为空,而非无参数调用
    if(!lodash.isEmpty(this.input) && typeof this.input === "string") {
        this.input = JSON.parse(this.input);
    }
}

2. 解决@Output()事件无法触发的问题

  • Angular的(okClicked)事件绑定语法仅在Angular模板中有效,插入到summernote的HTML属于原生DOM,无法被Angular解析。需将Angular的EventEmitter转为原生CustomEvent,并通过原生事件监听的方式绑定处理函数:
  • 修改组件的testButtonClicked方法,用原生事件替代EventEmitter:
testButtonClicked() {
    this.valueObject = {
        textVal : this.textVal,
        numberVal: this.numberVal
    };
    // 派发原生CustomEvent,将数据放在detail中
    this.dispatchEvent(new CustomEvent('okClicked', { detail: this.valueObject }));
}
  • 在插入元素后,获取DOM元素并绑定原生事件监听:
addSpecInstTestEl() {
    this.inputObj = {
        type: "input",
        label: "text field",
    };
    const html = `<spec-inst-test-element input='${JSON.stringify(this.inputObj)}'></spec-inst-test-element>`;
    this.specificInstructionRecord.specificInstruction += html;
    
    // 延迟获取元素(确保summernote已渲染插入的HTML)
    setTimeout(() => {
        const el = document.querySelector('spec-inst-test-element');
        if (el) {
            el.addEventListener('okClicked', (event: CustomEvent) => {
                this.testSpecOkClicked(event.detail);
            });
        }
    }, 0);
}

内容的提问来源于stack exchange,提问作者Chinmoy Chakraborty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 09:08:09