it-swarm.com.de

Angular Form Validation und Bootstrap-Stile

Ich bin ziemlich neu bei Angular und ich versuche ein Registrierungsformular mit Angular und Bootstrap 4 zu erstellen.

Das Ergebnis, das ich möchte, ist, die Stile von Bootstrap mit der Validierung von Angular zu verwenden. Genauer gesagt, wendet Angular bei der Validierung des Formulars Stile (ng-valid, ng-invalid usw.) an zwei verschiedenen Stellen an: das Eingabeelement und das Formularelement.

Zwei Fragen:

1) Da Bootstrap 'has-danger' und 'has-success' anstelle von 'ng- [in] valid' verwendet, ist es möglich, dass angle diese Stile anstelle des Standardstils verwendet. Derzeit erwäge ich die Erweiterung des Bootstraps durch Hinzufügen der Winkelstile (mit @extend has-danger/success).

2) Angular wendet den Stil auf die Eingabe- und Formularelemente an, während Bootstrap ihn für das Formulargruppenelement erwartet. Ist es möglich, den Stil anstelle des Eingabeelements (oder beides?) Dort anzuordnen?

Ich verwende reaktive Formulare und möchte Dinge vermeiden (nicht getestet):

<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>

Gibt es einen einfachen Weg (nicht zu ausführlich), um dies zu erreichen?

17
Rémi PIOTAIX

Wenn Sie SASS verwenden, können Sie Folgendes tun, ohne alle CSS neu schreiben zu müssen.

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

Hinweis: Sie müssen Bootstrap als Teil Ihres SASS-Builds importieren, anstatt direkt darauf zu verweisen.

Wenn Sie nicht mit SASS arbeiten, ist die Installation ziemlich hilfreich. Sehen Sie hier Angular CLI SASS-Optionen

16
Oliver

Eine weitere Option ist diese Direktive:

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

Es fügt einfach die is-invalid-Klasse zu jedem Feld hinzu, wenn das Feld berührt oder ungültig ist. Es verhält sich im Grunde genauso wie die SASS-Lösung von Oliver, kommt aber auch ohne SASS aus und hat möglicherweise eine kleinere kompilierte Ausgabe.

5
yankee

Die beste Idee, die mir beim Betrachten der eckigen Dokumente aufgefallen ist, ist die Verwendung einer Direktive .. __ Meine Implementierung funktioniert nur mit reaktiven Formularen und wenn das Element, auf das Sie den Stil anwenden möchten, das Formularsteuerelement enthält (wenn Sie Bootstrap verwenden ist der Fall). Sollte aus Gründen der Kompatibilität mit select und Textarea erweitert werden.

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

Beispiel:

Die Komponente:

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

Und seine Vorlage:

<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>
1
Rémi PIOTAIX