如果外部库修改了相应的dom本机元素值,则更新Angular 6表单值

如果外部库修改了相应的dom本机元素值,则更新Angular 6表单值,dom,angular6,angular-forms,controlvalueaccessor,Dom,Angular6,Angular Forms,Controlvalueaccessor,我正在尝试使用Angular 6表单进行协同浏览。在共同浏览开源库时,JS会更新远程方对应元素的DOM值。我在index.html中更新了togetherJS相关代码(两行,一行在head,另一行在body)我观察到使用ControlValueAccessor时,相应元素的表单类型DOM值正在更新,但视图中的FormControl值没有更新。 我的问题是如何将外部库对DOM元素所做的更改反映到视图中angular 6表单控件的元素值中 您可以从以下链接获取代码: 如何复制: 1.从上述链接下载

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

您可以从以下链接获取代码:

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

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


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

这个问题的答案在于angular(6)属性,它在shadow DOM上工作,只监听angular zone内发生的更改,当第三方库(如TogetherJS)更新DOM时,相应的更改不会影响angular组件,因为它们不订阅实际的DOM本机元素

为了解决此问题,我们采取了以下措施:

  • 在表单类构造函数中注册一个回调,以捕获从共同浏览库触发的DOM“更改”事件,即发生在角度区域之外,如下所述:
代码片段

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以执行以下操作:
    • 使用此.zone.Run()在角度上下文中运行
    • 使用ElementRef获取组件的模板选择器
    • 对输入元素运行queryselector,并与事件的outerHTML进行比较,以检查组件中的哪个元素已更改
    • 为匹配元素设置Formcontrol的值
PS:这里CustomPerform是实例的ControlValueAccesor FormGroup类型。在您的情况下,它可以是您的表单。我们可以在另一篇SO文章中提到的形式(如果是被动的)密钥遍历

代码段:

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