0

我正在尝试使用 Angular 6 Forms 进行协同浏览。在共同浏览开源库时,JS 会更新远程方对应元素的 DOM 值。我已经在 index.html 中更新了与 JS 相关的代码(头中的两行,正文中的另一行)我使用 ControlValueAccessor 观察到相应元素的表单类型 DOM 值正在更新,但 FormControl 值在视图中没有得到更新。我的问题是外部库对 DOM 元素所做的更改如何反映到角度 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 参数值在这种情况下。

4

1 回答 1

0

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

在此处输入图像描述

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

  • 在 Form 类构造函数中注册一个回调以捕获从 Co-Browsing 库触发的 DOM“<strong>change”事件,即发生在 angular zone 之外,如下所述:

代码片段

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:迭代反应式表单控件中所述

代码片段:

  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中的完整代码以供其他人阅读。

于 2018-09-20T00:45:32.267 回答