私のAngular 6 appでは、Reactive Formsを使用しています。
私の目的は、送信するとき、エラーが発生したときに最初の無効な入力にフォーカスを設定することです。
私のフォームは次のようになります:
<form [formGroup]="addItemfForm " (ngSubmit)="onSubmitForm()">
<div class="form-inline form-group">
<label class="col-md-2 justify-content-start">
Libellé du pef
<span class="startRequired mr-1"> *</span>
</label>
<input type="text"
maxlength="100"
formControlName="libellePef"
class="col-md-6 form-control"
placeholder="saisie obligatoire"
[ngClass]="{ 'is-invalid': submitted && formFiels.libellePef.errors }"/>
<div *ngIf="submitted && formFiels.libellePef.errors" class="col invalid-feedback">
<div class="col text-left" *ngIf="formFiels.libellePef.errors.required">Libellé du pef est requis.</div>
</div>
</div>
<div class="form-inline form-group">
<label class="col-md-2 justify-content-start">
Code Basicat
<span class="startRequired mr-1"> *</span>
</label>
<input type="text"
maxlength="100"
formControlName="codeBasicat"
class="col-md-3 form-control"
placeholder="saisie obligatoire"
[ngClass]="{ 'is-invalid': submitted && formFiels.codeBasicat.errors }"/>
<div *ngIf="submitted && formFiels.codeBasicat.errors" class="col invalid-feedback">
<div class="text-left" *ngIf="formFiels.codeBasicat.errors.required">Code Basicat est requis.</div>
</div>
</div>
<div class="form-inline form-group">
<label class="col-md-2 justify-content-start">
Nom de l'application
<span class="startRequired mr-1"> *</span>
</label>
<input type="text"
maxlength="100"
formControlName="nomApplication"
class="col-md-6 form-control"
placeholder="saisie obligatoire"
[ngClass]="{ 'is-invalid': submitted && formFiels.nomApplication.errors }"/>
<div *ngIf="submitted && formFiels.nomApplication.errors" class="col invalid-feedback">
<div class="text-left" *ngIf="formFiels.nomApplication.errors.required">Nom de l'application est requis.
</div>
</div>
</div>
</form>
TSファイルの下では、フォーム設定は次のようになります:
this.addItemfForm = this.formBuilder.group({
libellePef: ['', Validators.required],
codeBasicat: ['', Validators.required ],
nomApplication: ['', Validators.required ],
urlCible: [''],
modeTransfert: [''],
});
autofocusディレクティブを試しましたが、うまくいきませんでした
提案?
これを試して:
import { Directive, HostListener, ElementRef} from '@angular/core';
@Directive({
selector: '[focusFirstInvalidField]'
})
export class FocusFirstInvalidFieldDirective {
constructor(private el: ElementRef) { }
@HostListener('submit')
onFormSubmit() {
const invalidElements = this.el.nativeElement.querySelectorAll('.ng-invalid');
if (invalidElements.length > 0) {
console.log(invalidElements[0]);
invalidElements[0].focus();
}
}
}
デバッグすることを忘れないでください。要素0が私に起こったあなた自身のフォームではないかどうかを確認してください。
私の答えは yurzui の answer からインスピレーションを受けています。 nativeElement
を使用して、特定のFormControl
のFormControl
を取得するために、彼の答えのロジックを使用しています。
これはそれを行うロジックです:
_const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;
FormControlName.prototype.ngOnChanges = function () {
const result = originFormControlNameNgOnChanges.apply(this, arguments);
this.control.nativeElement = this.valueAccessor._elementRef.nativeElement;
return result;
};
_
これで、フォームのエラーフィールドは、フィールドが無効であってもnullになります。したがって、無効な最初のフィールドを正確に取得するには、すべてのフィールドをループ処理し、各フィールドの有効性を確認する必要があります。このロジックはonSubmitForm()
メソッドで記述できます。このようなもの:
_onSubmitForm() {
const fieldsToCheck = [
'codeBasicat',
'libellePef',
'nomApplication'
];
for (let i = 0; i < fieldsToCheck.length; i++) {
const fieldName = fieldsToCheck[i];
if (this.addItemfForm.get(fieldName).invalid) {
( < any > this.addItemfForm.get(fieldName)).nativeElement.focus();
break;
}
}
}
_
ループから抜け出したかったので、意図的に_Array.forEach
_の代わりにfor
を使用しました。
うまくいけば、これはあなたのためのトリックを行う必要があります。
参照用の WorkingサンプルStackBlitz .
私はディレクティブを使用してそれを行いました。したがって、私のフォームは次のようになります。
<form [formGroup]="userForm" (submit)="saveData()" appFocus >
...
</form>
ディレクティブ自体のコード:
import { Directive, HostListener, Input, ElementRef } from '@angular/core';
import { NgForm } from '@angular/forms';
@Directive({
selector: '[appFocus]'
})
export class FocusDirective {
constructor(private el: ElementRef) { }
@Input() formGroup: NgForm;
@HostListener('submit', ['$event'])
public onSubmit(event): void {
if ('INVALID' === this.formGroup.status) {
event.preventDefault();
const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng-invalid');
(<HTMLInputElement>formGroupInvalid[0]).focus();
}
}
}
ただし、考慮しなければならないコーナーケースが多数あるため、このソリューションは不完全です。たとえば、最初の要素がラジオボタングループの場合はどうなりますか。フォーカスイベントをディスパッチすると、フィールドが自動的にマークされます。次に、angular ads ng-invalidのすべての要素が入力になるわけではありません。
フォームのsubmit()にこのコードを記述するだけで、最初の無効な入力にフォーカスを設定できます。
if(this.form.invalid)
{
// Got focus to the error field
let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid'));
invalidFields[1].focus();
}
このオプションは私には機能しませんが、次のようにコードを変更することで修正できました。
@Directive({
selector: '[appErrorFocusin]'
})
export class ErrorFocusinDirective {
selectorToFocus : String = 'textArea,mat-select,select,input,button';
constructor(private el: ElementRef,
@Inject(DOCUMENT) private document: Document) { }
@Input() formGroup: NgForm;
@HostListener('submit', ['$event'])
public onSubmit(event): void {
if ('INVALID' === this.formGroup.status) {
event.preventDefault();
const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng- invalid,:not(.mat-badge-hidden).mat-badge');
let elementToOffset = this.getElementToOffset(formGroupInvalid[0]);
this.document.documentElement.scrollTop = elementToOffset.offsetTop;
this.setFocusOnError(elementToOffset);
}
}
getElementToOffset(element : any){
let defaultElement = element;
while (!(element.parentElement instanceof HTMLFormElement)){
if (element.parentElement){
element = element.parentElement;
}else{
return defaultElement;
}
}
return element;
}
setFocusOnError(elementToOffset : any){
let listaElementos = elementToOffset.querySelectorAll(this.selectorToFocus);
if (listaElementos.length>0){
listaElementos[0].focus();
}
}
}