Angular ReactiveForms: Tạo một mảng giá trị hộp kiểm?


104

Với một danh sách các hộp kiểm được liên kết với nhau formControlName, làm cách nào tôi có thể tạo ra một mảng các giá trị hộp kiểm được liên kết với formControl, thay vì chỉ đơn giản là true/ false?

Thí dụ:

<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 hiện đang sản xuất:

true or false

Những gì tôi muốn nó tạo ra:

['value-1', 'value-2', ...]

bạn đã tìm ra được giải pháp nào chưa?
CP

Đây có lẽ là cách được thiết kế kỹ lưỡng nhất để thực hiện các hộp kiểm trong một biểu mẫu từ trước đến nay. Điều này không đơn giản chút nào.
mwilson

8
Góc cạnh. Tất cả những gì tôi đang cố gắng làm là có được một nhóm radio liên kết ở dạng phản ứng của tôi. Tôi không nhớ đã đấu tranh nhiều với góc cạnh này. Tất cả các bài báo đều trỏ đến cùng một điều. Chỉ là không thể làm cho nó hoạt động. Mọi thứ khác đều siêu đơn giản. Có lẽ tôi đã nhìn nó quá lâu. Vẫn có cảm giác như quá phức tạp đối với một giá trị mảng trong một biểu mẫu.
mwilson

3
Vâng, thật khủng khiếp khi tôi hỏi điều này vào năm 2016 và nó vẫn còn khủng khiếp vào năm 2019.
ReactingToAngularVues

3
Tôi không thêm nhiều vào câu hỏi này, nhưng tôi muốn những người khác biết rằng tôi cũng cảm thấy như vậy. Chỉ riêng điều này đã là phần khó nhất trong việc học các dạng phản ứng góc. Tôi cảm thấy nó không khó như vậy chút nào. Tuy nhiên, tôi rất vui khi thấy mình không đơn độc trong cuộc đấu tranh. Vì vậy, cảm ơn vì đã đăng câu hỏi.
NorthStarCode

Câu trả lời:


52

Với sự trợ giúp của câu trả lời silentsod, tôi đã viết một giải pháp để nhận các giá trị thay vì các trạng thái trong formBuilder của tôi.

Tôi sử dụng một phương pháp để thêm hoặc xóa các giá trị trong formArray. Nó có thể là một cách tiếp cận tồi, nhưng nó hoạt động!

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

Khi tôi gửi biểu mẫu của mình, chẳng hạn như mô hình của tôi trông như sau:

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

Chỉ thiếu một thứ duy nhất, một hàm để điền vào formArray nếu mô hình của bạn đã có các giá trị được kiểm tra.


làm cách nào để kiểm tra xem hộp kiểm của tôi có được chọn hay không khi tôi tải dữ liệu sau khi sử dụng ví dụ của bạn để nhập vào db?
Devora

Trong giải pháp này, biểu mẫu luôn hợp lệ ngay cả khi hộp kiểm không được chọn
Teja

myChoices: new FormArray([], Validators.required)
Bikram Nath

48

Đây là một nơi tốt để sử dụng FormArray https://angular.io/docs/ts/latest/api/forms/index/FormArray-class.html

Để bắt đầu, chúng tôi sẽ xây dựng mảng điều khiển của chúng tôi với một FormBuilderhoặc mớiFormArray

Trình tạo Mẫu

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

FormArray mới

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

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

Dễ dàng để làm, nhưng sau đó chúng tôi sẽ thay đổi mẫu của mình và để công cụ tạo khuôn mẫu xử lý cách chúng tôi liên kết với các điều khiển của mình:

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>

Ở đây chúng tôi đang lặp lại tập hợp của FormControlschúng tôi trong của chúng tôi myValues FormArrayvà đối với mỗi điều khiển, chúng tôi liên kết [formControl]với điều khiển đó thay vì FormArrayđiều khiển và <div>{{checkboxGroup.controls['myValues'].value}}</div>tạo ra true,false,trueđồng thời làm cho cú pháp mẫu của bạn ít thủ công hơn một chút.

Bạn có thể sử dụng ví dụ này: http://plnkr.co/edit/a9OdMAq2YIwQFo7gixbj?p=preview để chọc ngoáy


1
có lẽ bạn nên loại bỏ id = "xxx", id phải là duy nhất phải không?
PeiSong Xiong

1
cho id có thể được sử dụng chỉ số *ngFor="let control of checkboxGroup.controls['myValues'].controls ; let i=index""
Mirza

9
Điều này thật tuyệt, nhưng tạo ra một mảng hộp kiểm hoàn toàn chung chung. Có lẽ bạn đang tải trong một mảng hoặc thứ gì đó khác và liên kết mỗi hộp kiểm với một số giá trị khác. Làm cách nào để bạn thêm, chẳng hạn, một chuỗi văn bản để sử dụng trong nhãn biểu mẫu vào mỗi điều khiển biểu mẫu?
Askdesigners

NM Tôi vừa ánh xạ nó bên cạnh một mảng bên ngoài: p
Askdesigners

@Askdesigners bạn có thể đăng giải pháp của mình để có các hộp kiểm và nhãn không?
eddygeek

25

Thực hiện điều này trong Angular 6 dễ dàng hơn đáng kể so với các phiên bản trước, ngay cả khi thông tin hộp kiểm được điền không đồng bộ từ API.

Điều đầu tiên cần nhận ra là nhờ vào keyvalueđường ống của Angular 6 mà chúng ta không cần phải sử dụng FormArraynữa, thay vào đó có thể lồng a FormGroup.

Đầu tiên, truyền FormBuilder vào hàm tạo

constructor(
    private _formBuilder: FormBuilder,
) { }

Sau đó khởi tạo biểu mẫu của chúng tôi.

ngOnInit() {

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

}

Khi dữ liệu tùy chọn hộp kiểm của chúng tôi có sẵn, hãy lặp lại nó và chúng tôi có thể đẩy nó trực tiếp vào lồng nhau FormGroupdưới dạng được đặt tên FormControl, mà không cần phải dựa vào mảng tra cứu được lập chỉ mục số.

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

Cuối cùng, trong mẫu, chúng ta chỉ cần lặp lại các keyvaluehộp kiểm: không bổ sung let index = i, và các hộp kiểm sẽ tự động theo thứ tự bảng chữ cái: gọn gàng hơn nhiều.

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

1
Rất hữu ích cũng như trong trường hợp một mảng giá trị hộp kiểm được mã hóa cứng đơn giản. Sau đó, bạn có thể thêm các hình thức kiểm soát bằng cách sử dụng tương tự cho vòng lặp ngay lập tức trong ngOnInit (), và các hộp kiểm bên trong mẫu của bạn tự động sẽ phản ánh các giá trị checkbox mảng
Arjan

3
Đây vẫn là đoạn trích [key1 = true, key2 = false, key3 = true]. Chúng tôi muốn ['key1', 'key3']
f.khantsis

@ f.khantsis Bạn có thể làm như vậy: `const value = {key1: true, key2: false, key3: true}; const list = Object.entries (value) .filter (([_, isSelected]) => isSelected) .map (([key]) => key); console.log (danh sách); `
zauni,

1
Giải pháp tốt nhất imho. Bạn có thể đặt nhiệm vụ const checkboxes = ..bên ngoài foreach;)
Bernoulli IT

Điều gì xảy ra khi khóa mục bằng cùng một thứ với một trường khác trên biểu mẫu? Ví dụ: tôi có hai mảng hộp kiểm khác nhau, mỗi mảng có các phím 'Nhỏ', 'Trung bình' và 'Lớn'?
Newclique

9

Nếu bạn đang tìm kiếm các giá trị hộp kiểm ở định dạng JSON

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

Ví dụ đầy đủ ở đây .

Tôi xin lỗi vì đã sử dụng Tên quốc gia làm giá trị hộp kiểm thay vì những giá trị trong câu hỏi. Giải thích thêm -

Tạo FormGroup cho biểu mẫu

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

Hãy để mỗi hộp kiểm là một FormGroup được xây dựng từ một đối tượng có thuộc tính duy nhất là giá trị của hộp kiểm.

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

Mảng Nhóm Biểu mẫu cho các hộp kiểm được sử dụng để đặt điều khiển cho 'quốc gia' trong Biểu mẫu mẹ.

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

Trong mẫu, sử dụng một đường ống để lấy tên cho điều khiển hộp kiểm

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

6

TL; DR

  1. Tôi thích sử dụng FormGroup để điền danh sách hộp kiểm
  2. Viết trình xác thực tùy chỉnh để kiểm tra ít nhất một hộp kiểm đã được chọn
  3. Ví dụ làm việc https://stackblitz.com/edit/angular-validate-at-least-one-checkbox-was-selected

Điều này đôi khi cũng khiến tôi bất ngờ vì vậy tôi đã thử cả hai cách tiếp cận FormArray và FormGroup.

Hầu hết thời gian, danh sách hộp kiểm được điền trên máy chủ và tôi nhận được thông qua API. Nhưng đôi khi bạn sẽ có một tập hợp hộp kiểm tĩnh với giá trị được xác định trước của bạn. Với mỗi trường hợp sử dụng, FormArray hoặc FormGroup tương ứng sẽ được sử dụng.

Về cơ bản FormArraylà một biến thể của FormGroup. Sự khác biệt chính là dữ liệu của nó được tuần tự hóa dưới dạng một mảng (trái ngược với việc được tuần tự hóa như một đối tượng trong trường hợp của FormGroup). Điều này có thể đặc biệt hữu ích khi bạn không biết có bao nhiêu điều khiển sẽ hiện diện trong nhóm, chẳng hạn như biểu mẫu động.

Để đơn giản hơn, hãy tưởng tượng bạn có một mẫu sản phẩm tạo đơn giản với

  • Một hộp văn bản tên sản phẩm bắt buộc.
  • Một danh sách các danh mục để lựa chọn, cần có ít nhất một danh mục được kiểm tra. Giả sử danh sách sẽ được truy xuất từ ​​máy chủ.

Đầu tiên, tôi thiết lập một biểu mẫu chỉ có tên sản phẩm formControl. Nó là một trường bắt buộc.

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

Vì danh mục đang hiển thị động, tôi sẽ phải thêm những dữ liệu này vào biểu mẫu sau khi dữ liệu đã sẵn sàng.

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

Có hai cách tiếp cận để xây dựng danh sách danh mục.

1. Mảng biểu mẫu

  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>

Điều này buildCategoryFormGroupsẽ trả lại cho tôi một FormArray. Nó cũng lấy danh sách giá trị đã chọn làm đối số, vì vậy Nếu bạn muốn sử dụng lại biểu mẫu để chỉnh sửa dữ liệu, nó có thể hữu ích. Với mục đích tạo form sản phẩm mới nên chưa thể áp dụng được.

Lưu ý rằng khi bạn cố gắng truy cập các giá trị formArray. Nó sẽ trông như thế nào [false, true, true]. Để có được danh sách các id đã chọn, cần phải thực hiện thêm một chút để kiểm tra từ danh sách nhưng dựa trên chỉ số mảng. Nghe có vẻ không tốt với tôi nhưng nó hoạt động.

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

Đó là lý do tại sao tôi sử dụng FormGroupcho vấn đề đó

2. Nhóm biểu mẫu

Sự khác biệt của formGroup là nó sẽ lưu trữ dữ liệu biểu mẫu dưới dạng đối tượng, yêu cầu một khóa và một điều khiển biểu mẫu. Vì vậy, bạn nên đặt khóa là CategoryId và sau đó chúng ta có thể truy xuất nó sau.

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>

Giá trị của nhóm biểu mẫu sẽ giống như sau:

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

Nhưng thường thì chúng ta chỉ muốn lấy danh sách các CategoryIds dưới dạng ["category2", "category3"]. Tôi cũng phải viết thư để lấy những dữ liệu này. Tôi thích cách tiếp cận này hơn so với formArray, bởi vì tôi thực sự có thể lấy giá trị từ chính biểu mẫu.

  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. Trình xác thực tùy chỉnh để kiểm tra ít nhất một hộp kiểm đã được chọn

Tôi đã thực hiện trình xác thực để kiểm tra ít nhất hộp kiểm X đã được chọn, theo mặc định, nó sẽ chỉ kiểm tra với một hộp kiểm.

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

6

Tôi không thấy giải pháp nào ở đây có thể trả lời hoàn toàn câu hỏi bằng cách sử dụng các biểu mẫu phản ứng ở mức độ tối đa, vì vậy đây là giải pháp của tôi cho điều tương tự.


Tóm lược

Đây là cốt lõi của lời giải thích chi tiết cùng với một ví dụ về StackBlitz.

  1. Sử dụng FormArraycho các hộp kiểm và khởi tạo biểu mẫu.
  2. valueChangesthể quan sát được hoàn hảo khi bạn muốn biểu mẫu hiển thị thứ gì đó nhưng lưu trữ thứ khác trong thành phần. Ánh xạ true/ falsegiá trị với các giá trị mong muốn ở đây.
  3. Lọc ra các falsegiá trị tại thời điểm gửi.
  4. Hủy đăng ký khỏi valueChangesquan sát được.

Ví dụ về StackBlitz


Giải thích chi tiết

Sử dụng FormArray để xác định biểu mẫu

Như đã đề cập trong câu trả lời được đánh dấu là đúng. FormArraylà cách để đi trong những trường hợp như vậy mà bạn muốn lấy dữ liệu trong một mảng. Vì vậy, điều đầu tiên bạn cần làm là tạo biểu mẫu.

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

Điều này sẽ chỉ đặt giá trị ban đầu của tất cả các hộp kiểm thành false.

Tiếp theo, chúng ta cần đăng ký các biến biểu mẫu này trong mẫu và lặp qua checkboxesmảng (KHÔNG PHẢI là FormArraydữ liệu hộp kiểm) để hiển thị chúng trong mẫu.

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

Tận dụng giá trị

Đây là phần tôi không thấy được đề cập trong bất kỳ câu trả lời nào được đưa ra ở đây. Trong những tình huống như thế này, nơi chúng tôi muốn hiển thị dữ liệu đã nói nhưng lưu trữ nó như một thứ khác, thì dữ liệu valueChangescó thể quan sát được sẽ rất hữu ích. Sử dụng valueChanges, chúng ta có thể quan sát những thay đổi trong checkboxesvà sau đó mapcác true/ falsegiá trị nhận được từ FormArraycác dữ liệu mong muốn. Lưu ý rằng điều này sẽ không thay đổi việc lựa chọn các hộp kiểm bên như bất kỳ truthy giá trị truyền cho hộp kiểm sẽ đánh dấu nó như là kiểm tra và ngược lại.

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

Về cơ bản, điều này ánh xạ các FormArraygiá trị vào checkboxesmảng ban đầu và trả về valuetrường hợp hộp kiểm được đánh dấu là true, nếu không, nó sẽ trả về false. Điều emitEvent: falsequan trọng ở đây là vì việc đặt FormArraygiá trị mà không có nó sẽ gây valueChangesra sự kiện tạo ra một vòng lặp vô tận. Bằng cách đặt emitEventthành false, chúng tôi đảm bảo rằng vật valueChangescó thể quan sát không phát ra khi chúng tôi đặt giá trị ở đây.

Lọc ra các giá trị sai

Chúng tôi không thể lọc trực tiếp các falsegiá trị trong FormArrayvì làm như vậy sẽ làm rối mẫu vì chúng được liên kết với các hộp kiểm. Vì vậy, giải pháp tốt nhất có thể là lọc ra các falsegiá trị trong quá trình gửi. Sử dụng toán tử spread để làm điều này.

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
}

Này về cơ bản lọc ra các falsy giá trị từ checkboxes.

Hủy đăng ký valueChanges

Cuối cùng, đừng quên hủy đăng ký valueChanges

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

Lưu ý: Có một trường hợp đặc biệt mà giá trị không thể được đặt thành FormArrayin valueChanges, tức là nếu giá trị hộp kiểm được đặt thành số 0. Điều này sẽ làm cho nó có vẻ như không thể chọn hộp kiểm vì việc chọn hộp kiểm sẽ đặt FormControllàm số 0(một giá trị giả) và do đó, không chọn hộp kiểm . Sẽ không được ưu tiên sử dụng số 0làm giá trị nhưng nếu bắt buộc, bạn phải đặt có điều kiện thành 0một giá trị trung thực nào đó, chẳng hạn như chuỗi '0'hoặc chỉ đơn giản truevà sau đó khi gửi, chuyển đổi nó trở lại số 0.

Ví dụ về StackBlitz

StackBlitz cũng có mã khi bạn muốn chuyển các giá trị mặc định vào các hộp kiểm để chúng được đánh dấu là đã chọn trong giao diện người dùng.


4

Tạo một sự kiện khi nó được nhấp và sau đó thay đổi thủ công giá trị true thành tên của hộp kiểm đại diện, khi đó tên hoặc true sẽ đánh giá như nhau và bạn có thể nhận tất cả các giá trị thay vì danh sách true / false. Ví dụ:

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

Điều này nắm bắt sự kiện sau khi nó đã được thay đổi thành true hoặc false bởi Angular Forms, nếu đúng, tôi đổi tên thành tên của hộp kiểm đại diện, nếu cần cũng sẽ đánh giá thành true nếu nó được kiểm tra là true / false như tốt.


Điều này đã giúp tôi đi đúng hướng, tôi đã thực hiện điều này this.customForm.patchValue ({[event.target.id]: event.target.checked});
Demodave

4

Nếu bạn muốn sử dụng biểu mẫu phản ứng Angular ( https://angular.io/guide/reactive-forms ).

Bạn có thể sử dụng một điều khiển biểu mẫu để quản lý giá trị đầu ra của nhóm hộp kiểm.

thành phần

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

Quản lý mô hình / trạng thái của đầu vào danh sách kiểm tra. Mô hình này cho phép bạn ánh xạ trạng thái hiện tại sang bất kỳ định dạng giá trị nào bạn cần.

Mô hình:

{
   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 Kiểm soát biểu mẫu

Điều khiển này lưu trữ giá trị muốn lưu như ví dụ:

giá trị đầu ra: "value_1,value_2"

Xem demo tại https://stackblitz.com/edit/angular-multi-checklist


Dễ dàng là giải pháp tốt nhất cho tôi. Cảm ơn bạn rất nhiều.
Newclique

2

Giải pháp của tôi - đã giải quyết nó cho Angular 5 với Material View
Kết nối thông qua

formArrayName = "thông báo"

(change) = "updateChkbxArray (n.id, $ event.checked, 'thông báo')"

Bằng cách này, nó có thể hoạt động cho nhiều mảng hộp kiểm trong một biểu mẫu. Chỉ cần đặt tên của mảng điều khiển để kết nối mỗi lần.

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>

Cuối cùng, bạn sẽ lưu biểu mẫu với mảng id bản ghi gốc để lưu / cập nhật. Giao diện người dùng

Phần liên kết của json của biểu mẫu

Sẽ rất vui khi có bất kỳ nhận xét để cải thiện.


0

PHẦN GHI NHỚ: -

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

PHẦN ĐIỀU KHIỂN: -

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

        }

1
Xin chào @EchoLogic .. Vui lòng cho tôi biết trong trường hợp có bất kỳ truy vấn nào
Abhishek Srivastava

1
Đây không phải là sử dụng ReactiveForms nhưng hình thức thường xuyên để không trả lời câu hỏi
Guillaume

0

Thêm 5 xu của tôi) Mô hình câu hỏi của tôi

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.