角度形式验证和引导样式

问题描述 投票:17回答:3

我对Angular很新,我正在尝试使用Angular和Bootstrap 4创建一个注册表单。

我想要的结果是使用Bootstrap的样式和Angular的验证。更准确地说,在验证表单时,Angular在两个不同的位置应用样式(ng-valid,ng-invalid等):input元素和表单元素。

两个问题:

1)由于Bootstrap使用'has-danger'和'has-success'而不是'ng- [in] valid',是否可以配置angular来使用这些样式而不是默认样式。目前,我正在考虑通过添加角度样式来扩展引导程序(使用@extend has-danger / success)

2)Angular将样式应用于输入和表单元素,而bootstrap则在form-group元素上使用它。是否可以将角度放在那里而不是输入元素(或两者?)

我正在使用反应形式,我想避免像(未经测试)这样的事情:

<form>
    <div class="form-group" [class.has-error]="!fg.get('username').valid" [class.has-success]="fg.get('username').valid">
        <label>Username</label>
        <input formControlName="username" type="text"/>
    </div>
</form>

实现这一目标有一种简单的方法(不是太冗长)吗?

css forms angular twitter-bootstrap-4
3个回答
18
投票

如果您正在使用SASS,则无需重写所有CSS即可执行以下操作。

.ng-touched.ng-invalid {
  @extend .is-invalid;
}

注意:您需要导入bootstrap作为SASS构建的一部分,而不是直接引用它。

如果您没有使用SASS,那么安装请参见Angular CLI SASS options


8
投票

另一个选择是这个指令:

import {Directive, HostBinding, Self} from '@angular/core';
import {NgControl} from '@angular/forms';

@Directive({
    selector: '[formControlName],[ngModel],[formControl]',
})
export class BootstrapValidationCssDirective {
    constructor(@Self() private cd: NgControl) {}

    @HostBinding('class.is-invalid')
    get isInvalid(): boolean {
        const control = this.cd.control;
        return control ? control.invalid && control.touched : false;
    }
}

如果字段被触摸或无效,它只是将is-invalid类添加到每个字段。它基本上与Oliver的SASS解决方案相同,但是在没有SASS的情况下也可以使用,并且可能还有较小的编译输出。


1
投票

在查看角度文档时,我遇到的最好的想法是使用指令。我的实现仅适用于Reactive表单,如果要应用该样式的元素包含表单控件(如果使用bootstrap则为该情况)。应该扩展以与select和textarea兼容。

import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms'

@Directive({ selector: '[formValidationStyle]' })
export class FormValidationStyleDirective implements OnInit {
  @Input('formValidationStyle') private formGroup: FormGroup;
  private component: FormControl;

  static VALID_STYLE: string = 'has-success';
  static INVALID_STYLE: string = 'has-danger';

  constructor(private el: ElementRef) { }

  ngOnInit(): void {
    let componentName: string;
    let inputElement = this.el.nativeElement.querySelector('input');
    if (inputElement) {
      componentName = inputElement.getAttribute('formControlName');
    }
    if (!componentName) {
      console.error('FormValidationStyleDirective: Unable to get the control name. Is the formControlName attribute set correctly?')
      return;
    }

    let control = this.formGroup.get(componentName)
    if (!(control instanceof FormControl)) {
      console.error(`FormValidationStyleDirective: Unable to get the FormControl from the form and the control name: ${componentName}.`)
      return;
    }
    this.component = control as FormControl;

    this.component.statusChanges.subscribe((status) => {
      this.onStatusChange(status);
    });
    this.onStatusChange(this.component.status);
  }

  onStatusChange(status: string): void {
    let cl = this.el.nativeElement.classList;

    if (status == 'VALID') {
      cl.add(FormValidationStyleDirective.VALID_STYLE)
      cl.remove(FormValidationStyleDirective.INVALID_STYLE)
    } else if (status == 'INVALID') {
      cl.add(FormValidationStyleDirective.INVALID_STYLE)
      cl.remove(FormValidationStyleDirective.VALID_STYLE)
    }
  }
}

例:

组件:

@Component({
  selector: 'security-register',
  templateUrl: './register.component.html'
})
export class RegisterComponent {
  registerForm: FormGroup;

  constructor(private http: Http, private fb: FormBuilder) {
    this.registerForm = this.fb.group({
       username: ['', Validators.required]
    });
  }
}

它的模板:

<form [formGroup]="registerForm" novalidate>
  <div class="form-group" [formValidationStyle]="registerForm">
    <label class="form-control-label" for="dbz-register-username">Login</label>
    <input formControlName="username" type="text" class="form-control" id="dbz-register-username" required>
  </div>
  <div class="form-group">
    <button type="submit" class="btn btn-primary">Register</button>
  </div>
</form>
© www.soinside.com 2019 - 2024. All rights reserved.