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

Angular子组件值传递问题:无法获取WYSIWYG编辑器(Summernote)的HTML内容值

解决Angular自定义Summernote编辑器无法传递值到父组件的问题

嘿,我看了你的代码,问题的核心是:你的app-editor自定义组件没有实现Angular表单的ControlValueAccessor接口,这导致父组件的FormControl无法和它进行双向的数据同步,所以你才会一直拿不到编辑器的HTML内容。

要解决这个问题,我们需要让子组件适配Angular的表单系统,具体步骤如下:

1. 实现ControlValueAccessor接口并注册提供者

首先,在SummernoteComponent中导入相关的表单接口,并实现ControlValueAccessor,同时在组件装饰器中注册NG_VALUE_ACCESSOR提供者,这样Angular才会把你的组件当成一个可复用的表单控件。

修改summernote.component.ts的顶部导入:

import { Component, Input, OnInit, forwardRef } from "@angular/core";
import { FormControl, FormGroup, Validators, ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { DomSanitizer } from "@angular/platform-browser";

然后更新组件装饰器,添加提供者:

@Component({
 selector: 'app-editor',
 templateUrl: './summernote.component.html',
 styleUrls: ['./summernote.component.css'],
 providers: [
  {
   provide: NG_VALUE_ACCESSOR,
   useExisting: forwardRef(() => SummernoteComponent),
   multi: true
  }
 ]
})

接下来让组件类实现ControlValueAccessor接口,并添加必要的方法和属性:

export class SummernoteComponent implements OnInit, ControlValueAccessor {
 showTemplateForm = true;
 // 移除原来的@Input() html,因为我们通过ControlValueAccessor处理值
 html?: string;
 form: FormGroup;
 config: any = { /* 你的配置保持不变 */ };
 editorDisabled = false;

 // ControlValueAccessor相关属性和方法
 private onChange: (value: string) => void = () => {};
 private onTouched: () => void = () => {};

 get sanitizedHtml() {
  return this.sanitizer.bypassSecurityTrustHtml(this.html || '');
 }

 constructor(private sanitizer: DomSanitizer) {
  this.form = new FormGroup({
   html: new FormControl('', Validators.required),
  });
  // 监听表单控件的变化,通知父组件
  this.form.get('html')?.valueChanges.subscribe(value => {
   this.html = value;
   this.onChange(value);
   this.onTouched();
  });
 }

 ngOnInit() {}

 // ControlValueAccessor方法:写入值到组件
 writeValue(value: string): void {
  this.html = value || '';
  this.form.get('html')?.setValue(this.html);
 }

 // ControlValueAccessor方法:注册值变化回调
 registerOnChange(fn: (value: string) => void): void {
  this.onChange = fn;
 }

 // ControlValueAccessor方法:注册触摸回调
 registerOnTouched(fn: () => void): void {
  this.onTouched = fn;
 }

 // ControlValueAccessor方法:设置组件禁用状态
 setDisabledState(isDisabled: boolean): void {
  this.editorDisabled = isDisabled;
  if (isDisabled) {
   this.form.get('html')?.disable();
  } else {
   this.form.get('html')?.enable();
  }
 }

 // 其他原有方法保持不变
 onBlur() {
  console.log('Blur');
  this.onTouched();
 }

 onDelete(file: { url: any; }) {
  console.log('Delete file', file.url);
 }

 summernoteInit(event: any) {
  console.log(event);
 }
}

2. 调整子组件模板的绑定

修改summernote.component.html中的textarea绑定,确保它和组件的form控件关联,同时移除原来的[(ngModel)](因为我们用Reactive Forms结合ControlValueAccessor):

<ng-container *ngIf="showTemplateForm">
 <form [formGroup]="form">
  <textarea name="html" formControlName="html" [ngxSummernote]="config"
   [ngxSummernoteDisabled]="editorDisabled"
   (blur)="onBlur()"
   (mediaDelete)="onDelete($event)"
   (summernoteInit)="summernoteInit($event)">
  </textarea>
 </form>
 <!-- 其他预览部分保持不变 -->
 <h3>Vorschau:</h3>
 <div [ngxSummernoteView]="html"></div>
 <h3>Code</h3>
 <pre>{{html}}</pre>
 <div *ngIf="!html || html === ''"> Required </div>
</ng-container>

3. 父组件的简化调整

在app.component.ts中,确保你导入了FormBuilder(看起来你之前漏了导入):

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';

@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
 htmlTest = "";
 form!: FormGroup;

 constructor(private fb: FormBuilder) {}

 ngOnInit(): void {
  this.createForm();
 }

 createForm() {
  this.form = this.fb.group({
   myEditor: new FormControl(this.htmlTest),
  })
 }

 get myEditor(): FormControl{
  return this.form.controls['myEditor'] as FormControl;
 }

 // 添加提交测试方法
 onSubmit() {
  console.log('编辑器内容:', this.myEditor.value);
 }
}

父组件模板app.component.html可以保持不变,但你可以点击提交按钮测试是否能获取值:

<form class="input-form" [formGroup]="form" (submit)="onSubmit()">
 <app-editor formControlName="myEditor"></app-editor>
 <button mat-raised-button color="primary" type="submit">Speichern</button>
</form>

为什么这样修改?

Angular的Reactive Forms需要自定义组件实现ControlValueAccessor接口来完成以下工作:

  • writeValue: 接收父组件传递过来的值,更新子组件内部状态
  • registerOnChange: 注册一个回调函数,当子组件值变化时通知父组件
  • registerOnTouched: 注册一个回调函数,标记控件为已触摸(比如失去焦点时)
  • setDisabledState: 响应父组件设置的禁用状态

通过这些方法,你的自定义编辑器组件就能和父组件的FormControl完全同步数据了,现在你点击提交按钮就能看到控制台输出编辑器的HTML内容了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 09:22:39