添加[(ngModel)]时触发DOMException:字符串包含无效字符错误求助
这个错误的根源很明确:[(ngModel)]是Angular专属的双向绑定语法糖,并不是标准的HTML属性,而原生DOM的setAttribute方法不允许属性名包含[和]这类特殊字符,所以直接设置会触发DOMException: String contains an invalid character。
为什么不能这么做?
Angular的[(ngModel)]本质上是[ngModel](属性绑定)和(ngModelChange)(事件绑定)的语法糖,它是由Angular框架解析处理的,不是浏览器能识别的原生属性。用原生DOM API直接操作这类Angular指令,完全不符合Angular的工作机制,自然会报错。
正确的处理方式
1. 首选:用Angular模板语法动态生成元素(最符合Angular规范)
如果你的需求是遍历一组数据生成输入框,直接在组件模板中使用*ngFor即可,Angular会自动帮你处理双向绑定:
<!-- 组件模板文件(比如xxx.component.html) --> <div *ngFor="let trans of transList"> <input class="form-control input-transparent" type="text" [(ngModel)]="trans.key" name="keys[]" > </div>
然后在组件类中维护transList数组:
// 组件类文件(比如xxx.component.ts) import { Component } from '@angular/core'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html' }) export class YourComponent { transList = [/* 你的trans数据数组 */]; }
2. 特殊场景下必须动态创建:使用Angular的Renderer2或动态组件API
如果因为某些特殊需求必须动态创建元素(不推荐,尽量用模板方式),可以使用Angular提供的Renderer2来操作,或者通过ComponentFactoryResolver创建动态组件,而不是用原生的document.createElement。
比如用Renderer2创建元素后,需要通过Angular的方式绑定ngModel,而不是直接设置属性:
import { Component, Renderer2, ElementRef } from '@angular/core'; @Component({ selector: 'app-your-component', template: '<div #container></div>' }) export class YourComponent { constructor(private renderer: Renderer2, private el: ElementRef) {} ngOnInit() { const container = this.el.nativeElement.querySelector('#container'); const keyInput = this.renderer.createElement('input'); // 设置原生属性和类 this.renderer.addClass(keyInput, 'form-control input-transparent'); this.renderer.setAttribute(keyInput, 'type', 'text'); this.renderer.setAttribute(keyInput, 'name', 'keys[]'); this.renderer.setProperty(keyInput, 'value', trans.key); // 注意:这里不能直接设置[(ngModel)],需要通过Angular的绑定机制 // 更合适的方式是创建一个包含ngModel的模板片段,然后插入到容器中 // 或者使用动态组件来实现双向绑定 this.renderer.appendChild(container, keyInput); } }
不过这种方式要实现双向绑定还是比较复杂,所以优先推荐第一种模板化的方案。
总结
永远不要用原生DOM操作去处理Angular的专属指令(比如[(ngModel)]、*ngFor等),Angular有自己的组件和模板机制来处理动态元素和数据绑定,遵循框架规范才能避免这类错误。
内容的提问来源于stack exchange,提问作者Hamid Aijaz

