Angular中使用Rete库继承后属性只读无法修改问题求助
问题
在Angular项目中使用Rete库构建编辑器时,可正常添加Node,但修改节点内值时触发错误:Cannot assign to read only property 'value' of object '[object Object]'。
自定义继承的Rete类代码
import { ClassicPreset, ConnectionBase, NodeBase } from 'rete'; export class ComposerNode< CustomPayload extends { name: string; id: string; }, Inputs extends { [key in string]?: ComposerSocket; } = { [key in string]?: ComposerSocket; }, Outputs extends { [key in string]?: ComposerSocket; } = { [key in string]?: ComposerSocket; }, Controls extends { [key in string]?: ComposerControl; } = { [key in string]?: ComposerControl; }> extends ClassicPreset.Node<Inputs, Outputs, Controls> implements NodeBase { nodePayload: CustomPayload; constructor(node: CustomPayload) { super(node.name); this.selected = false; this.nodePayload = node; } } export class ComposerConnection< Main extends { name: string; id: string; }, Source extends ComposerNode<Main> = ComposerNode<Main>, Target extends ComposerNode<Main> = ComposerNode<Main> > extends ClassicPreset.Connection<Source, Target> implements ConnectionBase { constructor( source: Source, sourceOutput: keyof Source['outputs'], target: Target, targetInput: keyof Target['inputs'] ) { super(source, sourceOutput, target, targetInput); } } export class ComposerSocket extends ClassicPreset.Socket { constructor(name: string) { super(name); } } export type InputControlOptions<N> = { label?: string; description?: string; readonly?: boolean; initial?: N; change?: (value: N) => void; }; export class ComposerControl extends ClassicPreset.Control { } export class ComposerBaseControl<T> extends ComposerControl { pKey: string; label: string; description?: string; options?: InputControlOptions<T>; value?: T; readonly: boolean; constructor(pKey: string, options?: InputControlOptions<T>) { super(); this.pKey = pKey; this.options = options; this.readonly = !!this.options?.readonly; if (this.options?.initial) { this.value = this.options.initial; } this.label = this.options?.label || 'Control'; this.description = this.options?.description; } setValue(value?: T): void { this.value = value; // ***** 错误触发位置 } } export class ComposerTextControl extends ComposerBaseControl<string> { } export class ComposerNumberControl extends ComposerBaseControl<number> { override setValue(value?: number): void { this.value = !value ? 0 : +value; } } export class ComposerDropdownControl extends ComposerBaseControl<string> { dropdownOptions: string[]; constructor(pKey: string, dropdownOptions: string[], options?: InputControlOptions<string>) { super(pKey, options); this.dropdownOptions = dropdownOptions; } } export class ComposerCheckboxControl extends ComposerBaseControl<boolean> { override setValue(value?: boolean): void { this.value = new Boolean(value).valueOf(); } }
错误信息
core.mjs:10592 ERROR TypeError: Cannot assign to read only property 'value' of object '[object Object]' at ComposerDropdownControl.setValue (composer.framework.ts:87:15) at ComposerDropdownControlComponent.onChange (composer-dropdown-control.component.ts:21:15) at ComposerDropdownControlComponent_Template_select_change_3_listener (composer-dropdown-control.component.html:4:15) at executeListenerWithErrorHandling (core.mjs:16778:16) at wrapListenerIn_markDirtyAndPreventDefault (core.mjs:16811:22) at HTMLSelectElement.<anonymous> (platform-browser.mjs:665:17) at _ZoneDelegate.invokeTask (zone.js:402:31) at core.mjs:10735:55 at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:10735:36) at _ZoneDelegate.invokeTask (zone.js:401:60)
已尝试添加Object.setPrototypeOf(this, ComposerNode.prototype),但未解决问题,怀疑继承实现有误。
解决方案
问题根因
Rete框架中,ClassicPreset.Control实例被添加到节点后,会被内部设置为只读(冻结)对象,直接修改实例的value属性会触发只读权限错误,这是Rete为保护编辑器内部状态一致性的设计。
修复步骤
- 移除Control实例自身的value存储:不在
ComposerBaseControl中直接保存value,改为通过回调将值传递到外部状态(比如Node的nodePayload、Angular组件属性或状态管理服务) - 通过回调更新状态:利用
InputControlOptions中的change回调,将值变更通知给外部,由外部负责更新实际存储位置
修改后的代码示例
调整ComposerBaseControl
export class ComposerBaseControl<T> extends ComposerControl { pKey: string; label: string; description?: string; options?: InputControlOptions<T>; readonly: boolean; constructor(pKey: string, options?: InputControlOptions<T>) { super(); this.pKey = pKey; this.options = options; this.readonly = !!this.options?.readonly; this.label = this.options?.label || 'Control'; this.description = this.options?.description; } setValue(value?: T): void { // 调用回调通知外部更新值,而非修改自身属性 this.options?.change?.(value); } }
在Angular组件中处理值变更
以ComposerDropdownControlComponent为例,将值绑定到组件属性,并更新Node的payload:
export class ComposerDropdownControlComponent { @Input() control: ComposerDropdownControl; @Input() node: ComposerNode<any>; selectedValue: string; ngOnInit() { // 从Node的payload初始化值,fallback到初始值 this.selectedValue = this.node.nodePayload[this.control.pKey] ?? this.control.options?.initial; } onChange(event: Event) { const value = (event.target as HTMLSelectElement).value; this.control.setValue(value); } }
创建Control时传入回调更新Node payload
// 创建下拉控件时,通过change回调更新Node的自定义payload const dropdownControl = new ComposerDropdownControl('type', ['option1', 'option2'], { initial: 'option1', change: (value) => { // 将值存储到Node的nodePayload中,此处不会触发只读错误 this.node.nodePayload.type = value; } });
补充说明
Rete的核心设计会冻结节点和控件实例,防止意外修改破坏编辑器状态。所有状态变更都应通过框架API或外部状态管理完成,避免直接修改控件实例的属性。
内容的提问来源于stack exchange,提问作者Abhishek Patil
相关产品推荐
相关产品推荐

