Search code examples
angularionic-frameworklifecycleshadow-dom

Automatically clear input from an element within ShadowDOM using Angular?


I am using Ionic to create an autocomplete input but am having an issue with the browser autofilling the input with invalid data. I need to be able to clear it using Angular.

PS: I have added automcomplete="off" but it is not respected.

Below is the HTML for Ionic's ion-input which I am trying to target:

<ion-input #inputElem
           [autocomplete]="enableBrowserAutoComplete ? 'on' : 'off'"
           [name]="name"
           (keyup)="getItems($event)"
           (tap)="handleTap($event)"
           [(ngModel)]="keyword"
           (ngModelChange)="updateModel($event)"
           (ionFocus)="onFocus($event)"
           (ionBlur)="onBlur($event)"></ion-input>

Within my component I have the updateModel() function which checks the input on changes and clears it if it is invalid. However, angular's change detection does not notice if the browser autofills.

Or, say if you manipulate it in the console:

$('input.searchbar-input.sc-ion-searchbar-md').value = 'J'

So I am trying to find a way to clear the keyword if there is not a valid selection. My most successful attempts is using life cycle hooks such as OnChanges, DoCheck, and AfterViewCheck, but clearing the keyword is not enough. I have to clear the input inside the shadow dom because the value did not propagate yet. So within the function I have to get the element using a promise (I suspect this is the real problem). Which "works" as long as I keep a break point within the lifecycle function. The second I remove the breakpoint the browser tab completely freezes.

@ViewChild(
  'inputElem',
  {
    read:   ElementRef,
    static: false
  }
)
private inputElem:ElementRef;

[..]

ngOnChanges():void {
    if (!this.hasFocus) {
      if (this.clearInvalidInput && this.selected === null) {
        if (this.keyword !== '') {
          this.keyword = '';
        }

        if (this.inputElem && this.inputElem.nativeElement) {
          this.inputElem.nativeElement.getInputElement().then(
              (element) => {
                if (element.value !== '') {
                  element.value = '';
                }
              }
          );
        }
     }
   }
}

I have posted a work around as an answer but am leaving this open as it feels very hacky.


Solution

  • I have found a workaround, but it is not a preferred solution.

    ngDoCheck() {
      if (this.inputElem && this.inputElem.nativeElement) {
        if (this.inputElem.nativeElement.children && this.inputElem.nativeElement.children.length !== 0) {
          if (this.inputElem.nativeElement.children[0].children && this.inputElem.nativeElement.children[0].children.length !== 0) {
            if (this.inputElem.nativeElement.children[0].children[0].value) {
              this.inputElem.nativeElement.children[0].children[0].value = '';
            }
          }
        }
      }
    }