Angular 2关注Click / Event后的第一个无效输入

时间:2016-12-15 20:43:55

标签: javascript angular angular2-forms angular2-directives

我有一个奇怪的要求,并希望得到一些帮助。

单击按钮(不提交)后,我需要关注表单的第一个找到的无效输入。表单相当大,因此屏幕需要滚动到第一个无效输入。

这个AngularJS答案将是我需要的,但是不知道这样的指令是否会成为Angular 2中的方法:

Set focus on first invalid input in AngularJs form

Angular 2的方法是什么?谢谢你的帮助!

9 个答案:

答案 0 :(得分:6)

这对我有用。这不是最优雅的解决方案,但是考虑到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。它只是通过.ng-invalid转到页面上带有document.querySelector()的第一个元素,该元素返回返回列表中的第一个元素。

要使用它

this.scrollIfFormHasErrors(this.form).then(() => {
  // Run any additional functionality if you need to. 
});

我也在Angular的Github页面上发布了此内容:https://github.com/angular/angular/issues/13158#issuecomment-432275834

答案 1 :(得分:5)

不幸的是我目前无法对此进行测试,因此可能存在一些错误,但应该主要在那里。 只需将其添加到表单中即可。

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');
      }
    }
  }
}

答案 2 :(得分:3)

如果您使用的是AngularMaterial,则MdInputDirective有一个focus()方法,可让您直接关注输入字段。

在您的组件中,只需使用@ViewChildren注释获取对所有输入的引用,如下所示:

@ViewChildren(MdInputDirective) inputs: QueryList<MdInputDirective>;

然后,将焦点设置在第一个无效输入上就像这样简单:

this.inputs.find(input => !input._ngControl.valid).focus()

答案 3 :(得分:2)

我不知道这是否有效,但这对我来说很有用。

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可访问表单指令的方法。 欢迎改进!!!

答案 4 :(得分: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();
            });
        }
      }
   }

答案 5 :(得分:2)

纯HTML解决方案。 如果您不需要滚动,只需关注第一个有效输入,我就使用:

public submitForm() {
    if(this.form.valid){
        // submit form
    } else {
        let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid'));
        invalidFields[1].focus();
    }
}

这是模板驱动的形式。我们关注invalidFields的第二个元素,因为它首先也是整个表单,也是无效的。

答案 6 :(得分:1)

我建议把它放在一个服务中,对我来说它的工作原理如下:

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();
    });
  }
}

答案 7 :(得分:1)

我创建了一个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>

希望有帮助! :)

答案 8 :(得分:1)

对于角材料, 下面为我​​工作

@ViewChildren(MatInput) inputs: QueryList <MatInput>;
this.inputs.find(input => !input.ngControl.valid).focus();