Angular ReactiveForms: Erstellen eines Arrays von Kontrollkästchenwerten?

103

formControlNameWie kann ich bei einer Liste von Kontrollkästchen, die an dasselbe gebunden sind, ein Array von Kontrollkästchenwerten erstellen, die an das gebunden sind formControl, anstatt einfach true/false ?

Beispiel:

<form [formGroup]="checkboxGroup">
    <input type="checkbox" id="checkbox-1" value="value-1" formControlName="myValues" />
    <input type="checkbox" id="checkbox-2" value="value-2" formControlName="myValues" />
    <input type="checkbox" id="checkbox-3" value="value-2" formControlName="myValues" />
</form>

checkboxGroup.controls['myValues'].value Derzeit produziert:

true or false

Was ich möchte, dass es produziert:

['value-1', 'value-2', ...]
Reagieren auf AngularVues
quelle
Hast du eine Lösung gefunden?
CP
Dies ist wahrscheinlich die am meisten überarbeitete Methode, um Kontrollkästchen in einer Form zu erstellen, die es je gab. Dies ist überhaupt nicht einfach.
Mwilson
8
Winkelig. Ich versuche nur, eine Mat-Radio-Gruppe dazu zu bringen, sich in meiner reaktiven Form zu binden. Ich erinnere mich nicht, dass ich so viel mit Winkel zu kämpfen hatte. Alle Artikel verweisen auf dasselbe. Ich kann es einfach nicht zum Laufen bringen. Alles andere ist super einfach. Ich habe es mir wahrscheinlich viel zu lange angesehen. Es fühlt sich immer noch so an, als wäre Wayyyyy zu komplex für einen Array-Wert in einer Form.
Mwilson
3
Ja, es war schrecklich, als ich dies im Jahr 2016 fragte, und es ist im Jahr 2019 immer noch schrecklich.
ReactingToAngularVues
3
Ich füge dieser Frage keine Tonne hinzu, aber ich wollte, dass anderen bekannt wird, dass es mir genauso geht. Dies allein war der schwierigste Teil beim Erlernen eckiger reaktiver Formen. Ich denke, es sollte überhaupt nicht so schwierig sein. Ich bin froh zu sehen, dass ich im Kampf nicht allein bin. Vielen Dank, dass Sie die Frage gestellt haben.
NorthStarCode

Antworten:

51

Mit Hilfe von Silentsod Answer habe ich eine Lösung geschrieben, um Werte anstelle von Zuständen in meinem formBuilder abzurufen.

Ich benutze eine Methode, um Werte im formArray hinzuzufügen oder zu entfernen. Es mag ein schlechter Ansatz sein, aber es funktioniert!

component.html

<div *ngFor="let choice of checks; let i=index" class="col-md-2">
  <label>
    <input type="checkbox" [value]="choice.value" (change)="onCheckChange($event)">
    {{choice.description}}
  </label>
</div>

component.ts

// For example, an array of choices
public checks: Array<ChoiceClass> = [
  {description: 'descr1', value: 'value1'},
  {description: "descr2", value: 'value2'},
  {description: "descr3", value: 'value3'}
];

initModelForm(): FormGroup{
  return this._fb.group({
    otherControls: [''],
    // The formArray, empty 
    myChoices: new FormArray([]),
  }
}

onCheckChange(event) {
  const formArray: FormArray = this.myForm.get('myChoices') as FormArray;

  /* Selected */
  if(event.target.checked){
    // Add a new control in the arrayForm
    formArray.push(new FormControl(event.target.value));
  }
  /* unselected */
  else{
    // find the unselected element
    let i: number = 0;

    formArray.controls.forEach((ctrl: FormControl) => {
      if(ctrl.value == event.target.value) {
        // Remove the unselected element from the arrayForm
        formArray.removeAt(i);
        return;
      }

      i++;
    });
  }
}

Wenn ich mein Formular abschicke, sieht mein Modell beispielsweise so aus:

  otherControls : "foo",
  myChoices : ['value1', 'value2']

Es fehlt nur eines: eine Funktion zum Ausfüllen des formArray, wenn Ihr Modell bereits geprüfte Werte hat.

Guymage
quelle
Wie überprüfe ich, ob mein Kontrollkästchen aktiviert ist, wenn ich die Daten lade, nachdem ich Ihr Beispiel für die Eingabe in db verwendet habe?
Devora
In dieser Lösung ist das Formular immer gültig, auch wenn das Kontrollkästchen nicht aktiviert ist
Teja
myChoices: new FormArray([], Validators.required)
Bikram Nath
48

Hier ist ein guter Ort, um die zu nutzen FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html zu verwenden

Zu Beginn werden wir unsere Steuerelemente entweder mit a FormBuilderoder mit a neu aufbauenFormArray

FormBuilder

this.checkboxGroup = _fb.group({
  myValues: _fb.array([true, false, true])
});

neues FormArray

let checkboxArray = new FormArray([
  new FormControl(true),
  new FormControl(false),
  new FormControl(true)]);

this.checkboxGroup = _fb.group({
  myValues: checkboxArray
});

Das ist einfach genug, aber dann werden wir unsere Vorlage ändern und die Vorlagen-Engine damit umgehen lassen, wie wir an unsere Steuerelemente binden:

template.html

<form [formGroup]="checkboxGroup">
    <input *ngFor="let control of checkboxGroup.controls['myValues'].controls"
    type="checkbox" id="checkbox-1" value="value-1" [formControl]="control" />     
  </form>

Hier iterieren wir über unsere Menge FormControlsin unserem myValues FormArrayund für jedes Steuerelement binden wir [formControl]an dieses Steuerelement anstatt an das FormArraySteuerelement und <div>{{checkboxGroup.controls['myValues'].value}}</div>produzierentrue,false,true während Ihre Vorlagensyntax ein wenig weniger manuell ist.

Sie können dieses Beispiel verwenden: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview , um herumzustöbern

silentsod
quelle
1
wahrscheinlich solltest du id = "xxx" entfernen, die id sollte eindeutig sein oder?
PeiSong Xiong
1
für ID könnte Index verwendet werden *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza
9
Das ist cool, erzeugt aber eine völlig generische Reihe von Kontrollkästchen. Vermutlich würden Sie in ein Array oder etwas anderes laden und jedes Kontrollkästchen einem anderen Wert zuordnen. Wie fügen Sie beispielsweise jedem Formularsteuerelement eine Textzeichenfolge zur Verwendung in einer Formularbezeichnung hinzu?
Askdesigners
NM Ich habe es gerade neben einem externen Array abgebildet: p
Askdesigners
@Askdesigners können Sie Ihre Lösung veröffentlichen, um die Kontrollkästchen und die Etiketten zu erhalten?
Eddygeek
25

In Angular 6 ist dies erheblich einfacher als in früheren Versionen, selbst wenn die Kontrollkästcheninformationen asynchron von einer API ausgefüllt werden.

Das erste, was zu erkennen ist, ist, dass keyvaluewir dank der Pipe von Angular 6 keine Verwendung FormArraymehr benötigen und stattdessen a verschachteln können FormGroup.

Übergeben Sie zunächst FormBuilder an den Konstruktor

constructor(
    private _formBuilder: FormBuilder,
) { }

Dann initialisieren Sie unser Formular.

ngOnInit() {

    this.form = this._formBuilder.group({
        'checkboxes': this._formBuilder.group({}),
    });

}

Wenn unsere Optionsfelddaten verfügbar sind, iterieren Sie sie und wir können sie direkt FormGroupals Namen in die verschachtelten Daten verschieben FormControl, ohne auf nummerindizierte Sucharrays angewiesen zu sein.

const checkboxes = <FormGroup>this.form.get('checkboxes');
options.forEach((option: any) => {
    checkboxes.addControl(option.title, new FormControl(true));
});

Schließlich müssen wir in der Vorlage nur keyvaluedie Kontrollkästchen durchlaufen: keine zusätzlichen let index = i, und die Kontrollkästchen werden automatisch in alphabetischer Reihenfolge angezeigt: viel sauberer.

<form [formGroup]="form">

    <h3>Options</h3>

    <div formGroupName="checkboxes">

        <ul>
            <li *ngFor="let item of form.get('checkboxes').value | keyvalue">
                <label>
                    <input type="checkbox" [formControlName]="item.key" [value]="item.value" /> {{ item.key }}
                </label>
            </li>
        </ul>

    </div>

</form>
Danny Pritchard
quelle
1
Sehr nützlich auch bei einem einfachen fest codierten Array von Kontrollkästchenwerten. Dann können Sie die Formularsteuerelemente mit einer ähnlichen for-Schleife sofort in ngOnInit () hinzufügen, und die Kontrollkästchen in Ihrem Formular spiegeln dynamisch das Array der Kontrollkästchenwerte wider
Arjan
3
Dies ist immer noch ein Auszug [key1 = true, key2 = false, key3 = true]. Wir wollen ['key1', 'key3']
f.khantsis
@ f.khantsis Sie können es so machen: `const value = {key1: true, key2: false, key3: true}; const list = Object.entries (Wert) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (Liste); `
Zauni
1
Beste Lösung imho. Sie können die Zuordnung const checkboxes = ..außerhalb des foreach platzieren;)
Bernoulli IT
Was passiert, wenn der Elementschlüssel mit einem anderen Feld im Formular identisch ist? Zum Beispiel habe ich zwei verschiedene Kontrollkästchen-Arrays mit den Schlüsseln 'Klein', 'Mittel' und 'Groß'?
Newclique
9

Wenn Sie nach Kontrollkästchenwerten im JSON-Format suchen

{ "name": "", "countries": [ { "US": true }, { "Germany": true }, { "France": true } ] }

Vollständiges Beispiel hier .

Ich entschuldige mich für die Verwendung von Ländernamen als Kontrollkästchenwerte anstelle der in der Frage angegebenen. Weitere Erklärung -

Erstellen Sie eine FormGroup für das Formular

 createForm() {

    //Form Group for a Hero Form
    this.heroForm = this.fb.group({
      name: '',
      countries: this.fb.array([])
    });

    let countries=['US','Germany','France'];

    this.setCountries(countries);}
 }

Jedes Kontrollkästchen sei eine FormGroup, die aus einem Objekt erstellt wurde, dessen einzige Eigenschaft der Wert des Kontrollkästchens ist.

 setCountries(countries:string[]) {

    //One Form Group for one country
    const countriesFGs = countries.map(country =>{
            let obj={};obj[country]=true;
            return this.fb.group(obj)
    });

    const countryFormArray = this.fb.array(countriesFGs);
    this.heroForm.setControl('countries', countryFormArray);
  }

Das Array von FormGroups für die Kontrollkästchen wird verwendet, um das Steuerelement für die 'Länder' im übergeordneten Formular festzulegen.

  get countries(): FormArray {
      return this.heroForm.get('countries') as FormArray;
  };

Verwenden Sie in der Vorlage eine Pipe, um den Namen für das Kontrollkästchen-Steuerelement abzurufen

  <div formArrayName="countries" class="well well-lg">
      <div *ngFor="let country of countries.controls; let i=index" [formGroupName]="i" >
          <div *ngFor="let key of country.controls | mapToKeys" >
              <input type="checkbox" formControlName="{{key.key}}">{{key.key}}
          </div>
      </div>
  </div>
Acid
quelle
6

TL; DR

  1. Ich bevorzuge die Verwendung von FormGroup, um die Liste der Kontrollkästchen zu füllen
  2. Schreiben Sie einen benutzerdefinierten Validator, um zu überprüfen, ob mindestens ein Kontrollkästchen aktiviert wurde
  3. Arbeitsbeispiel https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Dies fiel mir auch manchmal auf, so dass ich sowohl FormArray- als auch FormGroup-Ansätze ausprobierte.

Die Liste der Kontrollkästchen wurde die meiste Zeit auf dem Server ausgefüllt und ich habe sie über die API erhalten. Manchmal haben Sie jedoch ein statisches Kontrollkästchen mit Ihrem vordefinierten Wert. In jedem Anwendungsfall wird das entsprechende FormArray oder FormGroup verwendet.

Grundsätzlich FormArrayist eine Variante von FormGroup. Der Hauptunterschied besteht darin, dass seine Daten als Array serialisiert werden (im Gegensatz zu einer Serialisierung als Objekt bei FormGroup). Dies kann besonders nützlich sein, wenn Sie nicht wissen, wie viele Steuerelemente in der Gruppe vorhanden sein werden, z. B. dynamische Formulare.

Stellen Sie sich der Einfachheit halber vor, Sie hätten ein einfaches Produktformular zum Erstellen

  • Ein erforderliches Textfeld für den Produktnamen.
  • Für eine Liste der Kategorien, aus denen Sie auswählen können, muss mindestens eine überprüft werden. Angenommen, die Liste wird vom Server abgerufen.

Zuerst habe ich ein Formular mit nur dem Produktnamen formControl eingerichtet. Es ist ein Pflichtfeld.

this.form = this.formBuilder.group({
    name: ["", Validators.required]
});

Da die Kategorie dynamisch gerendert wird, muss ich diese Daten später in das Formular einfügen, nachdem die Daten fertig waren.

this.getCategories().subscribe(categories => {
    this.form.addControl("categoriesFormArr", this.buildCategoryFormArr(categories));
    this.form.addControl("categoriesFormGroup", this.buildCategoryFormGroup(categories));
})

Es gibt zwei Ansätze, um die Kategorieliste aufzubauen.

1. Formulararray

  buildCategoryFormArr(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormArray {
    const controlArr = categories.map(category => {
      let isSelected = selectedCategoryIds.some(id => id === category.id);
      return this.formBuilder.control(isSelected);
    })
    return this.formBuilder.array(controlArr, atLeastOneCheckboxCheckedValidator())
  }
<div *ngFor="let control of categoriesFormArr?.controls; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="control" />
    {{ categories[i]?.title }}
  </label>
</div>

Dies buildCategoryFormGroupgibt mir ein FormArray zurück. Es wird auch eine Liste ausgewählter Werte als Argument verwendet. Wenn Sie das Formular zum Bearbeiten von Daten wiederverwenden möchten, kann dies hilfreich sein. Für die Erstellung eines neuen Produktformulars ist es noch nicht anwendbar.

Beachten Sie dies, wenn Sie versuchen, auf die formArray-Werte zuzugreifen. Es wird so aussehen [false, true, true]. Um eine Liste der ausgewählten IDs zu erhalten, war etwas mehr Arbeit erforderlich, um sie anhand der Liste zu überprüfen, jedoch basierend auf dem Array-Index. Klingt für mich nicht gut, aber es funktioniert.

get categoriesFormArraySelectedIds(): string[] {
  return this.categories
  .filter((cat, catIdx) => this.categoriesFormArr.controls.some((control, controlIdx) => catIdx === controlIdx && control.value))
  .map(cat => cat.id);
}

Deshalb bin ich auf FormGroupdiese Sache gekommen

2. Formulargruppe

Der Unterschied der formGroup besteht darin, dass die Formulardaten als Objekt gespeichert werden, für das ein Schlüssel und ein Formularsteuerelement erforderlich sind. Es ist daher eine gute Idee, den Schlüssel als Kategorie-ID festzulegen, damit wir ihn später abrufen können.

buildCategoryFormGroup(categories: ProductCategory[], selectedCategoryIds: string[] = []): FormGroup {
  let group = this.formBuilder.group({}, {
    validators: atLeastOneCheckboxCheckedValidator()
  });
  categories.forEach(category => {
    let isSelected = selectedCategoryIds.some(id => id === category.id);
    group.addControl(category.id, this.formBuilder.control(isSelected));
  })
  return group;
}
<div *ngFor="let item of categories; let i = index" class="checkbox">
  <label><input type="checkbox" [formControl]="categoriesFormGroup?.controls[item.id]" /> {{ categories[i]?.title }}
  </label>
</div>

Der Wert der Formulargruppe sieht folgendermaßen aus:

{
    "category1": false,
    "category2": true,
    "category3": true,
}

Meistens möchten wir jedoch nur die Liste der Kategorie-IDs als erhalten ["category2", "category3"]. Ich muss auch ein Get schreiben, um diese Daten zu nehmen. Ich mag diesen Ansatz besser im Vergleich zum formArray, weil ich den Wert tatsächlich aus dem Formular selbst übernehmen könnte.

  get categoriesFormGroupSelectedIds(): string[] {
    let ids: string[] = [];
    for (var key in this.categoriesFormGroup.controls) {
      if (this.categoriesFormGroup.controls[key].value) {
        ids.push(key);
      }
      else {
        ids = ids.filter(id => id !== key);
      }
    }
    return ids;
  }

3. Benutzerdefinierter Validator zum Aktivieren mindestens eines Kontrollkästchens wurde aktiviert

Ich habe den Validator so eingestellt, dass mindestens das Kontrollkästchen X aktiviert ist. Standardmäßig wird nur ein Kontrollkästchen aktiviert.

export function atLeastOneCheckboxCheckedValidator(minRequired = 1): ValidatorFn {
  return function validate(formGroup: FormGroup) {
    let checked = 0;

    Object.keys(formGroup.controls).forEach(key => {
      const control = formGroup.controls[key];

      if (control.value === true) {
        checked++;
      }
    });

    if (checked < minRequired) {
      return {
        requireCheckboxToBeChecked: true,
      };
    }

    return null;
  };
}
trungk18
quelle
6

Ich sehe hier keine Lösung, die die Frage vollständig mit reaktiven Formen in vollem Umfang beantwortet. Hier ist meine Lösung dafür.


Zusammenfassung

Hier ist der Kern der detaillierten Erklärung zusammen mit einem StackBlitz-Beispiel.

  1. Verwenden Sie FormArrayfür die Kontrollkästchen und initialisieren Sie das Formular.
  2. Das valueChangesObservable ist perfekt, wenn Sie möchten, dass das Formular etwas anzeigt, aber etwas anderes in der Komponente speichert. Karte das true/false -Werte den gewünschten Werten zu.
  3. Filtern Sie die falseWerte zum Zeitpunkt der Übermittlung heraus.
  4. Abbestellen von valueChangesbeobachtbar.

StackBlitz Beispiel


Ausführliche Erklärung

Verwenden Sie FormArray, um das Formular zu definieren

Wie bereits in der Antwort als richtig markiert. FormArrayist der richtige Weg in solchen Fällen, in denen Sie die Daten lieber in einem Array abrufen möchten. Als erstes müssen Sie das Formular erstellen.

checkboxGroup: FormGroup;
checkboxes = [{
    name: 'Value 1',
    value: 'value-1'
}, {
    name: 'Value 2',
    value: 'value-2'
}];

this.checkboxGroup = this.fb.group({
    checkboxes: this.fb.array(this.checkboxes.map(x => false))
});

Dadurch wird nur der Anfangswert aller Kontrollkästchen auf gesetzt false.

Als nächstes müssen wir diese Formularvariablen in der Vorlage registrieren und über das checkboxesArray iterieren (NICHT die FormArrayDaten, sondern die Kontrollkästchen), um sie in der Vorlage anzuzeigen.

<form [formGroup]="checkboxGroup">
    <ng-container *ngFor="let checkbox of checkboxes; let i = index" formArrayName="checkboxes">
        <input type="checkbox" [formControlName]="i" />{{checkbox.name}}
    </ng-container>
</form>

Nutzen Sie die beobachtbaren valueChanges

Hier ist der Teil, den ich in keiner hier gegebenen Antwort erwähnt sehe. In solchen Situationen, in denen wir diese Daten anzeigen, aber als etwas anderes speichern möchten, ist das valueChangesObservable sehr hilfreich. Mit valueChangeskönnen wir die Änderungen in den checkboxesund dann mapdie true/ falseWerte beobachten, die von den FormArrayzu den gewünschten Daten empfangen wurden . Beachten Sie, dass dies die Auswahl der Kontrollkästchen nicht ändert, da ein an das Kontrollkästchen übergebener Wahrheitswert es als aktiviert markiert und umgekehrt.

subscription: Subscription;

const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
this.subscription = checkboxControl.valueChanges.subscribe(checkbox => {
    checkboxControl.setValue(
        checkboxControl.value.map((value, i) => value ? this.checkboxes[i].value : false),
        { emitEvent: false }
    );
});

Dies ordnet die FormArrayWerte im Wesentlichen dem ursprünglichen checkboxesArray zu und gibt das valuezurück, falls das Kontrollkästchen als markiert ist true, andernfalls wird es zurückgegeben false. Dies emitEvent: falseist hier wichtig, da das Setzen des FormArrayWerts ohne ihn dazu führt, dass valueChangesein Ereignis ausgegeben wird, das eine Endlosschleife erzeugt. Mit der Einstellung emitEventauf stellen falsewir sicher, dass das valueChangesObservable nicht emittiert, wenn wir den Wert hier einstellen.

Filtern Sie die falschen Werte heraus

Wir können die falseWerte in der nicht direkt filtern, FormArrayda dies die Vorlage durcheinander bringt, da sie an die Kontrollkästchen gebunden sind. Die bestmögliche Lösung besteht also darin, die falseWerte während der Übermittlung herauszufiltern . Verwenden Sie dazu den Spread-Operator.

submit() {
    const checkboxControl = (this.checkboxGroup.controls.checkboxes as FormArray);
    const formValue = {
        ...this.checkboxGroup.value,
        checkboxes: checkboxControl.value.filter(value => !!value)
    }
    // Submit formValue here instead of this.checkboxGroup.value as it contains the filtered data
}

Dies filtert im Grunde die falschen Werte aus dem herauscheckboxes .

Abbestellen von valueChanges

Vergessen Sie nicht, sich abzumelden valueChanges

ngOnDestroy() {
    this.subscription.unsubscribe();
}

Hinweis: Es gibt einen speziellen Fall , in dem ein Wert nicht auf den eingestellt wird , FormArrayin valueChanges, dh wenn das Kontrollkästchen Wert auf die Zahl gesetzt 0. Dadurch sieht es so aus, als ob das Kontrollkästchen nicht aktiviert werden kann, da durch Aktivieren des Kontrollkästchens die Option FormControlals Zahl 0(ein falscher Wert) festgelegt wird und das Kontrollkästchen daher deaktiviert bleibt. Es wäre vorzuziehen, die Zahl nicht 0als Wert zu verwenden, aber wenn dies erforderlich ist, müssen Sie bedingt 0auf einen wahrheitsgemäßen Wert setzen, z. B. Zeichenfolge '0'oder einfach nur, trueund ihn dann beim Senden wieder in die Zahl konvertieren 0.

StackBlitz Beispiel

Der StackBlitz verfügt auch über Code, wenn Sie Standardwerte an die Kontrollkästchen übergeben möchten, damit diese in der Benutzeroberfläche als aktiviert markiert werden.

nash11
quelle
4

Erstellen Sie ein Ereignis, wenn Sie darauf klicken, und ändern Sie den Wert von true manuell in den Namen des Kontrollkästchens. Dann wird der Name oder true gleich ausgewertet, und Sie können alle Werte anstelle einer Liste von true / false abrufen. Ex:

component.html

<form [formGroup]="customForm" (ngSubmit)="onSubmit()">
    <div class="form-group" *ngFor="let parameter of parameters"> <!--I iterate here to list all my checkboxes -->
        <label class="control-label" for="{{parameter.Title}}"> {{parameter.Title}} </label>
            <div class="checkbox">
              <input
                  type="checkbox"
                  id="{{parameter.Title}}"
                  formControlName="{{parameter.Title}}"
                  (change)="onCheckboxChange($event)"
                  > <!-- ^^THIS^^ is the important part -->
             </div>
      </div>
 </form>

component.ts

onCheckboxChange(event) {
    //We want to get back what the name of the checkbox represents, so I'm intercepting the event and
    //manually changing the value from true to the name of what is being checked.

    //check if the value is true first, if it is then change it to the name of the value
    //this way when it's set to false it will skip over this and make it false, thus unchecking
    //the box
    if(this.customForm.get(event.target.id).value) {
        this.customForm.patchValue({[event.target.id] : event.target.id}); //make sure to have the square brackets
    }
}

Dadurch wird das Ereignis abgefangen, nachdem es von Angular Forms bereits in true oder false geändert wurde. Wenn es true ist, ändere ich den Namen in den Namen des Kontrollkästchens, das bei Bedarf auch als true ausgewertet wird, wenn es auf true / false as überprüft wird Gut.

Kanada11
quelle
Dies brachte mich auf den richtigen Weg, und am Ende tat ich dies this.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave
4

Wenn Sie ein reaktives Angular-Formular verwenden möchten ( https://angular.io/guide/reactive-forms) ).

Sie können ein Formularsteuerelement verwenden, um den ausgegebenen Wert der Gruppe von Kontrollkästchen zu verwalten.

Komponente

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { flow } from 'lodash';
import { flatMap, filter } from 'lodash/fp';

@Component({
  selector: 'multi-checkbox',
  templateUrl: './multi-checkbox.layout.html',
})
export class MultiChecboxComponent  {

  checklistState = [ 
      {
        label: 'Frodo Baggins',
        value: 'frodo_baggins',
        checked: false
      },
      {
        label: 'Samwise Gamgee',
        value: 'samwise_gamgee',
        checked: true,
      },
      {
        label: 'Merry Brandybuck',
        value: 'merry_brandybuck',
        checked: false
      }
    ];

  form = new FormGroup({
    checklist : new FormControl(this.flattenValues(this.checklistState)),
  });


  checklist = this.form.get('checklist');

  onChecklistChange(checked, checkbox) {
    checkbox.checked = checked;
    this.checklist.setValue(this.flattenValues(this.checklistState));
  }

  flattenValues(checkboxes) {
    const flattenedValues = flow([
      filter(checkbox => checkbox.checked),
      flatMap(checkbox => checkbox.value )
    ])(checkboxes)
    return flattenedValues.join(',');
  }
}

html

<form [formGroup]="form">
    <label *ngFor="let checkbox of checklistState" class="checkbox-control">
    <input type="checkbox" (change)="onChecklistChange($event.target.checked, checkbox)" [checked]="checkbox.checked" [value]="checkbox.value" /> {{ checkbox.label }}
  </label>
</form>

checklistState

Verwaltet das Modell / den Status der Checklisteneingaben. Mit diesem Modell können Sie den aktuellen Status einem beliebigen Wertformat zuordnen.

Modell:

{
   label: 'Value 1',
   value: 'value_1',
   checked: false
},
{
  label: 'Samwise Gamgee',
  value: 'samwise_gamgee',
  checked: true,
},
{
  label: 'Merry Brandybuck',
  value: 'merry_brandybuck',
  checked: false
}

checklist Formularsteuerung

Dieses Steuerelement speichert den Wert, den Sie speichern möchten, z

Wertausgabe: "value_1,value_2"

Siehe Demo unter https://stackblitz.com/edit/angular-multi-checklist

Robert Prib
quelle
Einfach die beste Lösung für mich. Ich danke dir sehr.
Newclique
2

Meine Lösung - gelöst für Angular 5 mit Materialansicht
Die Verbindung erfolgt über die

formArrayName = "Benachrichtigung"

(change) = "updateChkbxArray (n.id, $ event.checked, 'Benachrichtigung')"

Auf diese Weise kann es für mehrere Kontrollkästchen-Arrays in einem Formular funktionieren. Legen Sie einfach den Namen des Steuerelement-Arrays fest, das jedes Mal eine Verbindung herstellen soll.

constructor(
  private fb: FormBuilder,
  private http: Http,
  private codeTableService: CodeTablesService) {

  this.codeTableService.getnotifications().subscribe(response => {
      this.notifications = response;
    })
    ...
}


createForm() {
  this.form = this.fb.group({
    notification: this.fb.array([])...
  });
}

ngOnInit() {
  this.createForm();
}

updateChkbxArray(id, isChecked, key) {
  const chkArray = < FormArray > this.form.get(key);
  if (isChecked) {
    chkArray.push(new FormControl(id));
  } else {
    let idx = chkArray.controls.findIndex(x => x.value == id);
    chkArray.removeAt(idx);
  }
}
<div class="col-md-12">
  <section class="checkbox-section text-center" *ngIf="notifications  && notifications.length > 0">
    <label class="example-margin">Notifications to send:</label>
    <p *ngFor="let n of notifications; let i = index" formArrayName="notification">
      <mat-checkbox class="checkbox-margin" (change)="updateChkbxArray(n.id, $event.checked, 'notification')" value="n.id">{{n.description}}</mat-checkbox>
    </p>
  </section>
</div>

Am Ende müssen Sie das Formular mit einer Reihe von IDs der Originaldatensätze speichern, die gespeichert / aktualisiert werden sollen. Die UI-Ansicht

Der relevante Teil des json des Formulars

Wir freuen uns über Verbesserungsvorschläge.

Tzvi Gregory Kaidanov
quelle
0

SCHABLONENTEIL: -

    <div class="form-group">
         <label for="options">Options:</label>
         <div *ngFor="let option of options">
            <label>
                <input type="checkbox"
                   name="options"
                   value="{{option.value}}"
                   [(ngModel)]="option.checked"
                                />
                  {{option.name}}
                  </label>
              </div>
              <br/>
         <button (click)="getselectedOptions()"  >Get Selected Items</button>
     </div>

CONTROLLER-TEIL: -

        export class Angular2NgFor {

          constructor() {
             this.options = [
              {name:'OptionA', value:'first_opt', checked:true},
              {name:'OptionB', value:'second_opt', checked:false},
              {name:'OptionC', value:'third_opt', checked:true}
             ];


             this.getselectedOptions = function() {
               alert(this.options
                  .filter(opt => opt.checked)
                  .map(opt => opt.value));
                }
             }

        }
Abhishek Srivastava
quelle
1
Hallo @EchoLogic .. Bitte lassen Sie mich im Falle einer Anfrage wissen
Abhishek Srivastava
1
Dies verwendet keine ReactiveForms, sondern reguläre Formulare, sodass die Frage nicht beantwortet wird
Guillaume
0

Addiere meine 5 Cent) Mein Fragenmodell

{
   name: "what_is_it",
   options:[
     {
      label: 'Option name',
      value: '1'
     },
     {
      label: 'Option name 2',
      value: '2'
     }
   ]
}

template.html

<div class="question"  formGroupName="{{ question.name }}">
<div *ngFor="let opt of question.options; index as i" class="question__answer" >
  <input 
    type="checkbox" id="{{question.name}}_{{i}}"
    [name]="question.name" class="hidden question__input" 
    [value]="opt.value" 
    [formControlName]="opt.label"
   >
  <label for="{{question.name}}_{{i}}" class="question__label question__label_checkbox">
      {{opt.label}}
  </label>
</div>

component.ts

 onSubmit() {
    let formModel = {};
    for (let key in this.form.value) {
      if (typeof this.form.value[key] !== 'object') { 
        formModel[key] = this.form.value[key]
      } else { //if formgroup item
        formModel[key] = '';
        for (let k in this.form.value[key]) {
          if (this.form.value[key][k])
            formModel[key] = formModel[key] + k + ';'; //create string with ';' separators like 'a;b;c'
        }
      }
    }
     console.log(formModel)
   }
Chemaxa
quelle