ログインページをAngular反応型フォームで実装しています。フォームが無効な場合、ボタン「ログイン」は無効になります。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'signin',
templateUrl: './signin.component.html'
})
export class SignInComponent implements OnInit {
private signInForm: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit() {
this.buildForm();
}
private buildForm(): void {
this.signInForm = this.formBuilder.group({
userName: ['', [Validators.required, Validators.maxLength(50)]],
password: ['', [Validators.required, Validators.maxLength(50)]]
});
this.signInForm.valueChanges
.subscribe((data: any) => this.onValueChanged(data));
this.onValueChanged();
}
private onValueChanged(data?: any) {
console.log(data);
}
そのため、ブラウザで起動すると、「userName」フィールドと「passwords」フィールドが事前に入力されています。そして、コンソールには値 '{userName: "[email protected]"、パスワード: ""}'があり、結果としてボタン "login"は無効になっています。しかし、ページのどこかをクリックするとonValueChangedがトリガーされ、 '{userName: "[email protected]"、password: "123456"}'、およびボタン「ログイン」が有効になります。
シークレットモードにした場合。事前に入力されたフィールドはありません(空です)が、値を入力(選択)すると、コンソールに '{userName: "[email protected]"、password: "123456が表示されます"} '、ボタン「ログイン」は追加のクリックなしで有効になります。
異なるイベントかもしれませんか?オートフィルとオートコンプリート?そしてangularはそれらとは異なる動作をしますか?
それを解決する最良の方法は何ですか?そして、なぜonValueChanged関数はブラウザがフィールドを自動入力するときに一度だけ実行されるのですか?
Chromeブラウザの問題:自動入力後(ユーザーがページをクリックする前)のパスワードフィールドの値へのアクセスを許可しません。したがって、2つの方法があります。
autocomplete="new-password"
を使用できることがわかりました
記載されているとおり here
このようにして、パスワードフィールドはまったく自動入力されず、それが私の場合でした。上記のリンクで利用可能な他の多くのオートコンプリート属性があります。
Chrome v58.0.3029.96で同じ問題に直面しました。検証と自動補完を維持するための回避策を次に示します。
export class SigninComponent extends UIComponentBase
{
//--------------------------------------------------------------------------------------------
// CONSTRUCTOR
//--------------------------------------------------------------------------------------------
constructor(viewModel: SigninViewModel)
{
super(viewModel);
// Autofill password Chrome bug workaround
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
{
this._autofillChrome = true;
this.vm.FormGroup.valueChanges.subscribe(
(data) =>
{
if (this._autofillChrome && data.uname)
{
this._password = " ";
this._autofillChrome = false;
}
});
}
}
//--------------------------------------------------------------------------------------------
// PROPERTIES
//--------------------------------------------------------------------------------------------
private _password: string;
private _autofillChrome: boolean;
//--------------------------------------------------------------------------------------------
// COMMAND HANDLERS
//--------------------------------------------------------------------------------------------
private onFocusInput()
{
this._autofillChrome = false;
}
}
そして私のHTMLで:
<input mdInput
[placeholder]="'USERNAME_LABEL' | translate"
[formControl]="vm.FormGroup.controls['uname']"
(focus)="onFocusInput()" />
[...]
<input mdInput
type="password"
[placeholder]="'PASSWORD_LABEL' | translate"
[formControl]="vm.FormGroup.controls['password']"
(focus)="onFocusInput()"
[(ngModel)]="_password" />
役に立てば幸いです。
注:vm
はUIComponentBase
で定義され、コンポーネントのビューモデルSigninViewModel
を参照します。 FormGroup
インスタンスは、ビジネスモデルがアプリケーションのビューから厳密に分離されているため、ビューモデルで定義されています。
[〜#〜] update [〜#〜]
V59以降、フィールドの自動補完時に入力のフォーカスイベントが発生するようです。したがって、上記の回避策はもう機能しません。タイムアウトを使用して、フィールドが自動補完によって更新されるのかユーザーによって更新されるのかを判断するための更新された回避策を次に示します(より良い方法は見つかりませんでした)。
export class SigninComponent extends UIComponentBase
{
//--------------------------------------------------------------------------------------------
// CONSTRUCTOR
//--------------------------------------------------------------------------------------------
constructor(viewModel: SigninViewModel)
{
super(viewModel);
// Autofill password Chrome bug workaround
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
{
this._autofillChrome = true;
setTimeout(
() =>
{
this._autofillChrome = false;
},
250 // 1/4 sec
);
this.vm.FormGroup.valueChanges.subscribe(
(data) =>
{
if (this._autofillChrome && data.uname)
{
this._password = " ";
this._autofillChrome = false;
}
});
}
}
//--------------------------------------------------------------------------------------------
// PROPERTIES
//--------------------------------------------------------------------------------------------
private _password: string;
private _autofillChrome: boolean;
}
そして私のHTMLで:
<input mdInput
[placeholder]="'USERNAME_LABEL' | translate"
[formControl]="vm.FormGroup.controls['uname']" />
[...]
<input mdInput
type="password"
[placeholder]="'PASSWORD_LABEL' | translate"
[formControl]="vm.FormGroup.controls['password']"
[(ngModel)]="_password" />
回避策を見つけました
Var isDisabledを作成します:boolean = false UPDATE:1.1もう1つ-var initCount:number = 0;
ngOnInit():void {this.isDisabled = false; this.initCount ++; }
メソッドを作成する
そして、これはコードです:
// This method will be called async
onStart(): Observable<boolean> {
if (this.loginFomrControl.hasError('required') &&
this.passwordFormControl.hasError('required') && this.initCount == 1) {
this.isDisabled = false;
// increase init count so this method wound be called async
this.initCount++;
}
return new BehaviorSubject<boolean>(true).asObservable();
}
// This method will ve called on change
validateForm() {
if (this.loginFormControl.value != '' && this.passwordFormControl.value != '') {
this.isDisabled = false;
} else if (this.loginFomrControl.value == '' || this.passwordFormControl.value == '') {
this.isDisabled = true;
}
}
これがHTMLのサンプルです
<div class="container" *ngIf="onStart() | async">
<!-- Do Stuff -->
<mat-form-field class="login-full-width">
<input matInput placeholder="{{ 'login_email' | translate }}" id="login_email" [formControl]="loginFomrControl" (change)="validateForm()">
<mat-error *ngIf="loginFomrControl.hasError('email') && !loginFomrControl.hasError('required')">
{{'login_email_error' | translate}}
</mat-error>
<mat-error *ngIf="loginFomrControl.hasError('required')">
{{ 'login_email' | translate }}
<strong>{{ 'login_required' | translate }}</strong>
</mat-error>
</mat-form-field>
<!-- Do Stuff -->
</div>
これは私のために働いています
1。before(itの自動入力)
<div class="form-group form-row required">
<input class="input p-l-20 form-control" formControlName='otp' type="text" name="otp" placeholder="Enter OTP">
</div>
2。after(現在は自動充填ではなく、正常に動作しています)
<div class="form-group form-row required">
<input class="input p-l-20 form-control" formControlName='otp' type="text" name="otp" placeholder="Enter OTP">
<!-- this dummy input is solved my problem -->
<input class="hide" type="text">
</div>
注 hide is bootstrap v4 class
完全を期すために:私は非反応的なログインフォームを持っています。
_<form name="loginForm" role="form" (ngSubmit)="onLoginSubmit()">
<input name="username" #usernameInp>
<input type="password" name="password" #passwordInp>
<button type="submit">Login</button>
</form>
_
[(ngModel)]="username"
を使用する場合、ブラウザautofill機能が起動しても、関連するコンポーネントの変数username
は読み込まれません。
したがって、代わりにViewChildを使用します。
_@ViewChild('usernameInp') usernameInp: ElementRef;
@ViewChild('passwordInp') passwordInp: ElementRef;
...
onLoginSubmit() {
const username = this.usernameInp.nativeElement.value;
const password = this.passwordInp.nativeElement.value;
...
_
このようにして、ユーザーがLoginをクリックすると、ブラウザーが提供する値にアクセスできます。
私のソリューション Gist Hub
// <ion-input (change)="fixAutoFill($event, 'password')" #passwordInput autocomplete="off" formControlName="password" type="password"></ion-input>
// <ion-input (change)="fixAutoFill($event, 'username')" #usernameInput autocomplete="off" type="text" formControlName="username"></ion-input>
fixAutoFill(event, type) {
const value = event.target.value;
if (type === 'username') {
this.loginForm.patchValue({
username: value
}, {emitEvent: true, onlySelf: false});
} else {
this.loginForm.patchValue({
password: value
}, {emitEvent: true, onlySelf: false});
}
// console.log('after click', this.loginForm.value);
}
@ViewChild('usernameInput') usernameInput: IonInput;
@ViewChild('passwordInput') passwordInput: IonInput;
これを試してください。少し頭を悩ませましたが、これでうまくいきました。
input:-webkit-autofill {
-webkit-transition-delay: 99999s;
}