2016-09-24 19 views
6

Ich bekomme nicht, wie Checkbox-Gruppen in einer modellgetriebenen Form in angular2 behandelt werden sollen.Checkbox Gruppenbehandlung und Validierung in Angular2

Das Modell verfügt über eine Eigenschaft languages, die ich so instanziiert:

this.model = { 
    languages: [] 
}; 

FormBuilder Mit dem Formular zu erstellen:

this.modelForm = this.formBuilder.group({ 
    'languages': [model.languages, Validators.required], 
}); 

Und die Vorlage:

<div *ngFor="let language of translateService.get('languages') | async | key_value"> 
    <input type="checkbox" name="languages[]" formControlName="languages" value="{{ language.key }}" id="language_{{ language.key }}"> 
    <label attr.for="language_{{ language.key }}">{{ language.value }}</label> 
</div> 

Die div wird für Stylingzwecke benötigt (benutzerdefinierte che ckbox), key_value macht natürlich Schlüssel und Werte der Sprache in der Schleife verfügbar.

Das erste Problem kommt mit der Validierung. Wenn ein Kontrollkästchen aktiviert und deaktiviert wird (und kein anderes Kontrollkästchen aktiviert ist), ist die Eingabe immer noch gültig - irgendwie seltsam.

Das zweite Problem kommt mit dem Wert, der true ist, wenn zwei oder mehr Sprachen überprüft werden und false andernfalls.

Dann gibt es ein drittes Problem mit dem Anfangswert von languages, die nur ein leeres Array ist, aber alle Kontrollkästchen zunächst überprüft werden (passiert nicht, wenn der Anfangswert auf string festgelegt ist), obwohl ich kann Stellen Sie keine checked Attribut im DOM.

Ich arbeite mit der neuesten ionischen Beta (2.0.0-Beta.10), die angular/core Version 2.0.0-rc.4 und angular/forms Version 0.2.0 verwendet.

Gibt es eine Anleitung zur Arbeit mit Checkbox-Gruppen? Irgendwelche Ratschläge oder Ideen?

Antwort

6

Das erste Problem kommt mit der Validierung. Wenn ein Kontrollkästchen aktiviert und deaktiviert wird (und kein anderes Kontrollkästchen aktiviert ist), ist die Eingabe immer noch gültig - irgendwie seltsam.

ich bemerkt, dass, wenn der Wert von languages ein leeres Array ist, ist es die Validations.required Prüfung besteht.

Das zweite Problem kommt mit dem Wert, der wahr ist, wenn zwei oder mehr Sprachen überprüft und andernfalls falsch sind.

Dann gibt es ein drittes Problem mit dem Anfangswert von Sprachen, die nur ein leeres Array ist, aber alle Kontrollkästchen zunächst überprüft werden (passiert nicht, wenn der Anfangswert auf eine Zeichenfolge festgelegt ist), obwohl ich kann kein überprüftes Attribut im DOM erkennen.

Ich denke, das Problem ist die Art und Weise Sie mehrere Steuerelemente zu einem einzigen FormControl sind verbindlich, glaube ich, ein FormArray Bedürfnisse einbezogen werden, möglicherweise mit einem anderen FormControl das Ergebnis Ihrer Checkbox Array zu speichern.

Gibt es eine Anleitung zur Arbeit mit Checkbox-Gruppen? Irgendwelche Ratschläge oder Ideen?

Sicher, ich nahm einen Stich bei der Implementierung, ich werde die Implementierung zunächst von einigen Notizen gefolgt posten. Sie können ihn in Aktion sehen hier bei https://plnkr.co/edit/hFU904?p=preview

@Component({ 
    template: ` 
    <template [ngIf]="loading"> 
     Loading languages... 
    </template> 
    <template [ngIf]="!loading"> 
     <form [formGroup]="modelForm"> 
     <div [formArrayName]="'languages'" [class.invalid]="!modelForm.controls.selectedLanguages.valid"> 
      <div *ngFor="let language of modelForm.controls.languages.controls; let i = index;" [formGroup]="language"> 
      <input type="checkbox" formControlName="checked" id="language_{{ language.controls.key.value }}"> 
      <label attr.for="language_{{ language.controls.key.value }}">{{ language.controls.value.value }}</label> 
      </div> 
     </div> 
     <hr> 
     <pre>{{modelForm.controls.selectedLanguages.value | json}}</pre> 
     </form> 
    </template> 
    ` 
}) 
export class AppComponent { 
    loading:boolean = true; 
    modelForm:FormGroup; 
    languages:LanguageKeyValues[]; 

    constructor(public formBuilder:FormBuilder){ 
    } 

    ngOnInit() { 

     this.translateService.get('languages').subscribe((languages:LanguageKeyValues[]) => { 

     let languagesControlArray = new FormArray(languages.map((l) => { 
      return new FormGroup({ 
      key: new FormControl(l.key), 
      value: new FormControl(l.value), 
      checked: new FormControl(false), 
      }); 
     })); 

     this.modelForm = new FormGroup({ 
      languages: languagesControlArray, 
      selectedLanguages: new FormControl(this.mapLanguages(languagesControlArray.value), Validators.required) 
     }); 

     languagesControlArray.valueChanges.subscribe((v) => { 
      this.modelForm.controls.selectedLanguages.setValue(this.mapLanguages(v)); 
     }); 

     this.loading = false; 
     }); 
    } 

    mapLanguages(languages) { 
     let selectedLanguages = languages.filter((l) => l.checked).map((l) => l.key); 
     return selectedLanguages.length ? selectedLanguages : null; 
    } 
} 

Der wichtigste Unterschied ist, dass ich Ihre model.languages in Ihre modelForm verschmolzen, und jetzt auf dem modelForm.languagesFormArray in der Vorlage am wiederholen.

modelForm.languages wurde modelForm.selectedLanguages und ist nun ein berechneter Wert basierend auf den überprüften Werten in modelForm.languages. Wenn nichts ausgewählt ist, wird modelForm.selectedLanguages auf Null gesetzt, um die Validierung zu verhindern.

modelForm ist nicht instanziert bis Sprachen verfügbar sind, ist dies meist persönliche Präferenz, ich bin sicher, dass Sie asynchron languages und selectedLanguages zu Ihrem modelForm befestigen könnte, aber es vereinfacht die Dinge es synchron zu konstruieren.

Ich nahm translateService.get('languages') | async, bemerkte ich einige seltsame Verhalten mit dieser Funktion in der Vorlage aufgerufen wird, und ich bevorzuge meine Observables in der Komponente trotzdem auszupacken, um Lade/Fehlerzustände zu erfassen.

Es ist nicht so elegant wie einige native Checkbox-Array-Formular-Steuerelement könnte sein, aber es ist sauber und sehr flexibel. Schauen Sie sich the plunker an und lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben!

+1

ich es versucht, es hat funktioniert, und oh mein Gott, so dass, wenn wir mehr als eine Checkbox Gruppe haben, sind wir praktisch verrückt reaktive Formen zu verwenden, : / – Ayyash

1

Wenn Sie ein Kontrollkästchen aktivieren und es dann deaktivieren, zeigt das FormControl es weiterhin als gültig an, obwohl es nicht markiert ist. Es kann vorkommen, dass es nur die wahre und falsche values.You nimmt kann diese Probe von Code versuchen, wie es für mich gearbeitet -

       mustBeChecked(control: FormControl): {[key: string]: string} { 
           if (!control.value) { 
           return {mustBeCheckedError: 'Must be checked'}; 
           } else { 
             return null; 
             } 
           } 

Sie können auch auf diese beziehen plunker

Es gibt derzeit eine offene Frage Hier wird das Klickereignis ausgelöst, bevor der Wert geändert wird. Siehe den GitHub-Link here .Hope Es kann Ihnen helfen.

Es gibt verschiedene Abhilfen für mehrere Kontrollkästchen wie mit

event.target.checked 

anstelle des Wertes aus dem Modell.

Sie es, wie in diesem Beispiel verwenden können -

  <input type="checkbox" 
       (change)="expression && expression.Option1=$event.target.checked ? true : undefiend" 
       [ngModel]="expression?.Option1"> 
      <input type="checkbox" 
       (change)="expression && expression.Option2=$event.target.checked ? true : undefiend" 
       [ngModel]="expression?.Option2">