I am experimenting cobrowsing with Angular 6 Forms.In co-browsing an opensource library togetherJS updates the DOM value of corresponding element for remote party.I have updated togetherJS related code in index.html(two line one in head and another in body) I have observed using ControlValueAccessor Form type DOM value of corresponding element is getting updated but FormControl value is not getting updated in view. My question is how changes done by an external library on DOM elements can be reflected into angular 6 form control's element value in view.
One can get the code from below link: https://github.com/srigaurav1986/Angular-Forms.git
How to reproduce:
1.Download code from above link.
2.Install dependencies using "npm install"
3.Run "ng serve -o"
4.open in browser "http://localhost:4200/controlvalueaccessor"
5.Click on "Start TogetherJs"
6.Copy the popped link in another browser window.
7.Update the "Name" field
We can see DOM field value is also getting updated on remote side but after pressing "Submit" button we can see FormControl value remains unaltered on remote side but changed on other side.
I tried using manually detecting changes using application.tick,markforcheck() and detectchanges() apis but no luck.Is there a way, where we can listen to some event on DOM element change and subscribe to it and also update the Formcontrol parameter values in such case.
The answer to this question lies in angular(6) property that it works on shadow DOM and only listen to the changes happening within angular zone , when the third party library like TogetherJS updates DOM corresponding changes doesn't effect angular components as they are not subscribe to actual DOM native element.
In order to resolve this issue we did following :
Code Snippet
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));
})
}
PS: Here customerForm is ControlValueAccesor FormGroup type of instance. In your case it can be your form. We can generalize form( In case reactive) key traversal as mentioned in another SO post Angular 2: Iterate over reactive form controls
Code Snippet:
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();
})
}
This will set the respective values of elements(obviously via traversing loop) changed in component and validation should not fail as it’s happening in current context. The core idea of above details is how to capture change events happening outside angular zone and updating angular application accordingly.
PS : I shall update the full code in github for other's perusal.