私には奇妙な要件があり、助けを望んでいました。
ボタンをクリックした後(送信ではなく)最初に見つかったフォームの無効な入力に注目する必要があります。フォームはかなり大きいため、画面を最初の無効な入力までスクロールする必要があります。
このAngularJSの答えは私が必要とするものですが、このようなディレクティブがAngular 2:
AngularJsフォームの最初の無効な入力にフォーカスを設定
Angularこれを行う2つの方法は何ですか?すべての助けをありがとう!
これは私のために機能します。最もエレガントなソリューションではありませんが、Angular特定のタスク、それは仕事をします。
_scrollTo(el: Element): void {
if(el) {
el.scrollIntoView({ behavior: 'smooth' });
}
}
scrollToError(): void {
const firstElementWithError = document.querySelector('.ng-invalid');
this.scrollTo(firstElementWithError);
}
async scrollIfFormHasErrors(form: FormGroup): Promise <any> {
await form.invalid;
this.scrollToError();
}
_
これは機能し、DOMの操作を回避できます。戻りリストの最初の要素を返すdocument.querySelector()
を介して、ページ上の_.ng-invalid
_で最初の要素に移動します。
それを使用するには:
_this.scrollIfFormHasErrors(this.form).then(() => {
// Run any additional functionality if you need to.
});
_
私はこれをAngularのGithubページにも投稿しました: https://github.com/angular/angular/issues/13158#issuecomment-432275834
残念ながら、現時点ではこれをテストできないため、いくつかのバグがあるかもしれませんが、ほとんどはそこにあるはずです。フォームに追加するだけです。
import {Directive, Input, HostListener} from '@angular/core';
import {NgForm} from '@angular/forms';
@Directive({ selector: '[scrollToFirstInvalid]' })
export class ScrollToFirstInvalidDirective {
@Input('scrollToFirstInvalid') form: NgForm;
constructor() {
}
@HostListener('submit', ['$event'])
onSubmit(event) {
if(!this.form.valid) {
let target;
for (var i in this.form.controls) {
if(!this.form.controls[i].valid) {
target = this.form.controls[i];
break;
}
}
if(target) {
$('html,body').animate({scrollTop: $(target.nativeElement).offset().top}, 'slow');
}
}
}
}
これが有効なアプローチであるかどうかはわかりませんが、これはうまく機能しています。
import { Directive, Input, HostListener, ElementRef } from '@angular/core';
import { NgForm } from '@angular/forms';
import * as $ from 'jquery';
@Directive({ selector: '[accessible-form]' })
export class AccessibleForm {
@Input('form') form: NgForm;
constructor(private el: ElementRef) {
}
@HostListener('submit', ['$event'])
onSubmit(event) {
event.preventDefault();
if (!this.form.valid) {
let target;
target = this.el.nativeElement.querySelector('.ng-invalid')
if (target) {
$('html,body').animate({ scrollTop: $(target).offset().top }, 'slow');
target.focus();
}
}
}
}
HTMLで
<form [formGroup]="addUserForm" class="form mt-30" (ngSubmit)="updateUser(addUserForm)" accessible-form [form]="addUserForm"></form>
これには、angularjsのアクセス可能なフォームディレクティブのアプローチが混在しています。改善を歓迎します!!!
AngularMaterial を使用している場合、MdInputDirectiveにはfocus()メソッドがあり、入力フィールドに直接焦点を合わせることができます。
コンポーネントでは、次のように @ ViewChildren アノテーションを使用して、すべての入力への参照を取得します。
@ViewChildren(MdInputDirective) inputs: QueryList<MdInputDirective>;
次に、最初の無効な入力にフォーカスを設定するのは次のように簡単です。
this.inputs.find(input => !input._ngControl.valid).focus()
プレーンHTMLソリューション。スクロールする必要がない場合は、最初の有効な入力に焦点を合わせてください:
public submitForm() {
if(this.form.valid){
// submit form
} else {
let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid'));
invalidFields[1].focus();
}
}
これは、テンプレート駆動型のフォームです。 invalidFieldsの2番目の要素に焦点を当てています。最初は無効なフォーム全体です。
@HostListener('submit', ['$event'])
onSubmit(event) {
event.preventDefault();
if (!this.checkoutForm.valid) {
let target;
target = $('input[type=text].ng-invalid').first();
if (target) {
$('html,body').animate({ scrollTop: $(target).offset().top }, 'slow', ()=> {
target.focus();
});
}
}
}
この問題を解決するためにAngularディレクティブを作成しました。ここで確認できます ngx-scroll-to-first-invalid 。
手順:
1.モジュールをインストールします。
npm i @ismaestro/ngx-scroll-to-first-invalid --save
2. NgxScrollToFirstInvalidModule
をインポートします。
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {NgxScrollToFirstInvalidModule} from '@ismaestro/ngx-scroll-to-first-invalid';
@NgModule({
imports: [
BrowserModule,
NgxScrollToFirstInvalidModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
3.フォーム内でディレクティブを使用します。
<form [formGroup]="testForm" ngxScrollToFirstInvalid>
<input id="test-input1" type="text" formControlName="someText1">
<button (click)="saveForm()"></button>
</form>
それが役に立てば幸い! :)
これをサービスに入れることをお勧めします、私にとっては次のように機能しました:
if (this.form.valid) {
//submit
} else {
let control;
Object.keys(this.form.controls).reverse().forEach( (field) => {
if (this.form.get(field).invalid) {
control = this.form.get(field);
control.markAsDirty();
}
});
if(control) {
let el = $('.ng-invalid:not(form):first');
$('html,body').animate({scrollTop: (el.offset().top - 20)}, 'slow', () => {
el.focus();
});
}
}