Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Angular 2在单击/事件后聚焦于第一个无效输入_Javascript_Angular_Angular2 Forms_Angular2 Directives - Fatal编程技术网

Javascript Angular 2在单击/事件后聚焦于第一个无效输入

Javascript Angular 2在单击/事件后聚焦于第一个无效输入,javascript,angular,angular2-forms,angular2-directives,Javascript,Angular,Angular2 Forms,Angular2 Directives,我有一个奇怪的要求,希望得到一些帮助 我需要关注在单击按钮(非提交)后第一次发现的无效表单输入。表单相当大,因此屏幕需要滚动到第一个无效输入 这个AngularJS答案正是我需要的,但我不知道Angular2中这样的指令是否合适: 做这件事的方法是什么?谢谢你的帮助 不幸的是,我目前无法测试这一点,因此可能会有一些bug,但大部分都应该存在。 只需将其添加到表单中 import {Directive, Input, HostListener} from '@angular/core'; imp

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

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

这个AngularJS答案正是我需要的,但我不知道Angular2中这样的指令是否合适:


做这件事的方法是什么?谢谢你的帮助

不幸的是,我目前无法测试这一点,因此可能会有一些bug,但大部分都应该存在。 只需将其添加到表单中

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');
      }
    }
  }
}
如果正在使用,MdInputDirective有一个focus()方法,允许您直接关注输入字段

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

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();
    });
  }
}
@ViewChildren(MdInputDirective)输入:QueryList

然后,在第一个无效输入上设置焦点如下所示:


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

我建议将其放入服务中,对我来说,它的工作方式如下:

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

我不知道这是否是有效的方法,但这对我来说非常有效

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

这对我来说很有效。这不是最优雅的解决方案,但考虑到我们都在这项特定任务中遇到的角度限制,它可以完成任务

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

我还在Angular的Github页面上发布了这篇文章:

我创建了一个Angular指令来解决这个问题。你可以在这里查一下

步骤:

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>

希望有帮助! :)

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

public submitForm() {
    if(this.form.valid){
        // submit form
    } else {
        let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid'));
        invalidFields[1].focus();
    }
}
这是为模板驱动的形式在这里。我们关注无效场的第二个元素,因为第一个是整个形式,它也是无效的。

对于角材料, 下面的方法对我有用

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

很抱歉反应太晚,我将对此进行测试!谢谢你的帮助!没有jquery我们怎么能做到这一点呢?你可以在不设置动画的情况下移动到元素,或者你可以编写自己的自定义动画函数(或者使用其他人)。类似这样的内容()这不起作用,target.nativeElement未定义。您使用的是哪个版本的Angular@Baconbeastnz?@Dunos查看此链接:这不是一个奇怪的要求。在具有许多字段的表单中,在提交时将第一个无效字段滚动到视图中是非常友好的。如果用户按下submit按钮时没有一个无效字段可见,他们将不知道为什么什么都没有发生。这很好地工作,除了在模式中有一个表单,在主页下面有其他控件之外。通常,modals会附加到DOM中,因此主页上的任何无效控件都会更高。将ng touch添加到选择器并确保调用markAllAsTouched()会有帮助,但用户仍可以在主页上触摸控件,然后打开模式。感谢您的反馈@AdamMarshall。同意,带有模态的场景可能需要一些额外的逻辑。