[Angular] モバイルSafariでもinputでの自動入力を検知する
というツイートを見つけて、そういえば記事化してなかったので対応方法をまとめておきます。モバイルSafari(WKWebView)の不具合なのですが、まだ修正行われていないんですよね。ちなみにCordova/Capacitorか、もしくは自作のWebViewアプリをつくってない限り、この不具合は関係ありません。
以下の説明はion-inputでしていますが、Issueをみる感じ、通常のinputでも再現するようです。
なぜ発生するのか
autocompleteでの入力を検知してもInputイベントを発生させてくれないからです。
どうやって直すか
Changeイベントは発生するので、Changeイベントを検知して値を渡します。
<ion-input #emailInput [(ngModel)]="email" type="email" name="email"></ion-input>
という要素があるとして、これをautocompleteに対応させましょう。基本的なAngularのComponentをベースに説明します。
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
+ public email = '';
+ @ViewChild('emailInput', { static: true }) emailInput: IonInput;
}
まず要素の値を email
というプロパティでバインディングします。また 要素に #emailInput
という名前をつけてるので、 ViewChild
を使ってこの要素を、 emailInput
というプロパティで参照します。続いて、この要素の change
イベントを監視します。
+ async ngOnInit() {
+ const nativeEmailInput = await this.emailInput.getInputElement();
+ nativeEmailInput.addEventListener('change', (ev: Event) => {
+ requestAnimationFrame(() => {
+ this.email = (ev.target as HTMLInputElement).value;
+ });
+ });
+ }
ion-input
は、ラップされているinput要素を getInputElement
メソッドで取得することができるので、ライフサイクル ngOnInit
が実行された時に this.emailInput.getInputElement()
でinput要素を取得します。そして、 addEventListener
で change
イベントを監視し、検知した値を email
プロパティにいれるようにします。
ただ問題はこの対応って「ユーザが通常入力してもchangeイベントが走り続けて、値が更新される」ことなんですよね。なので、requestAnimationFrame
を使って、通常のバインディング後に change
イベントの値が入るようにしています。ただあまりスマートではないので、例えば「ユーザが入力しかけたあとにautocompleteを使うシチューションは除外する」と割り切るなら
async ngOnInit() {
const nativeEmailInput = await this.emailInput.getInputElement();
nativeEmailInput.addEventListener('change', (ev: Event) => {
if (this.email.length === 0) {
this.email = (ev.target as HTMLInputElement).value;
};
});
}
というように、 email
プロパティが空の場合にしか値が入らないようにするとか、「最初のchangeイベントだけでいい」なら、すぐremoveListenerしてしまうという方法もあります。
対応するIssue: https://github.com/ionic-team/ionic-framework/issues/23335
ブラウザの不具合対応なので少し不格好になってしまいますが、参考になれば幸いです。
それではまた。
Discussion