【问题标题】:Updating Angular 6 Form value in case corresponding dom native element value is modified by external library如果外部库修改了相应的 dom 本机元素值,则更新 Angular 6 Form 值
【发布时间】:2019-02-07 22:57:14
【问题描述】:

我正在尝试使用 Angular 6 Forms 共同浏览。在共同浏览开源库时,JS 更新了远程方相应元素的 DOM 值。我已经更新了 index.html 中的 JavaScript 相关代码(两行第一行,另一行在body) 我使用 ControlValueAccessor 观察到相应元素的表单类型 DOM 值正在更新,但 FormControl 值在视图中没有得到更新。 我的问题是如何将外部库对 DOM 元素所做的更改反映到 Angular 6 表单控件的元素值中。

可以从以下链接获取代码: https://github.com/srigaurav1986/Angular-Forms.git

如何复制:
1.从以上链接下载代码。
2.使用“npm install”安装依赖
3.运行“ng serve -o”
4.在浏览器中打开“http://localhost:4200/controlvalueaccessor
5.点击“Start TogetherJs”
6.将弹出的链接复制到另一个浏览器窗口中。
7.更新“名称”字段

我们可以看到远程端的 DOM 字段值也在更新,但是在按下“提交”按钮后,我们可以看到 FormControl 的值在远程端保持不变,但在另一端发生了变化。

我尝试使用 application.tick、markforcheck() 和 detectchanges() api 手动检测更改,但没有运气。有没有办法,我们可以监听 DOM 元素更改的某些事件并订阅它并更新这种情况下的 Formcontrol 参数值。

【问题讨论】:

    标签: dom angular6 angular-forms controlvalueaccessor


    【解决方案1】:

    这个问题的答案在于 angular(6) 属性,它适用于 shadow DOM 并且只监听 angular zone 内发生的变化,当像 TogetherJS 这样的第三方库更新 DOM 时,相应的变化不会影响角度组件他们没有订阅实际的 DOM 原生元素。

    为了解决这个问题,我们做了以下工作:

    • 在 Form 类构造函数中注册一个回调,以捕获从协同浏览库触发的 DOM “change”事件,即发生在如下所述的角度区域之外:

    代码片段

    constructor(private formBuilder: FormBuilder,private elementRef: ElementRef,private _renderer: Renderer,private cdr:ChangeDetectorRef,private  app:ApplicationRef,private zone:NgZone) {
                zone.runOutsideAngular(() =>{
    
                window.document.addEventListener('change', this.change.bind(this));
    
            })
        }
    
    • 定义 eventHandler 以执行以下操作:
      • 使用 this.zone.run() 在 Angular 上下文中运行
      • 使用 ElementRef 获取组件的模板选择器。
      • 对输入元素运行 queryselector 并与事件的 outerHTML 进行比较,以检查组件中哪个元素发生了变化。
      • 为匹配元素设置 Formcontrol 的值。

    PS:这里的customerForm 是ControlValueAccesor FormGroup 类型的实例。在您的情况下,它可以是您的表格。我们可以概括形式(以防反应)键遍历,如另一篇 SO 帖子中所述 Angular 2: Iterate over reactive form controls

    代码片段:

      change(event){
            event.preventDefault();
            console.log("DOM value changed" ,event);
            console.log("component value", this.elementRef.nativeElement);
            this.zone.run(() => { console.log('Do change detection here');
            //this.cdr.detectChanges();
            if(this.elementRef.nativeElement.querySelectorAll('input')[0].outerHTML === event.target.outerHTML)
            {
                console.log('Inside value updation');
                //this.customerForm.controls.name.value=event.target.value;
                this.customerForm.controls['name'].setValue(event.target.value);
            }
        });
            setTimeout(() =>{
                this.cdr.markForCheck();
    
            })
    
        }
    

    这将设置组件中更改的元素的相应值(显然是通过遍历循环),并且验证不应失败,因为它发生在当前上下文中。 上述细节的核心思想是如何捕捉发生在角度区域之外的变化事件并相应地更新角度应用程序。

    PS:我将在 github 中更新完整代码以供其他人阅读。

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-29
      • 2016-07-09
      相关资源
      最近更新 更多