将ngModel绑定到动态复选框列表:Angular 2 / Typescript

时间:2017-04-24 19:46:48

标签: angular typescript dynamic checkboxlist ngmodel

我不确定绑定和更新动态生成复选框的模型的正确方法。 (这是一个最初使用Yeoman生成器创建的Angular 2的ASP.NET Core项目)或者我刚刚发现的一个简单的复选框。

下面是精简代码,它有一个工具和时间段。每个设施可以有多个时隙。时间段复选框列表显示正常。初始数据表明只应检查一个时隙。但是当我加载一个设施时,所有的时间段都会被检查。他们没有像我预期的那样与ngModel绑定。

  1. 如何修复它,以便只检查设施数据中包含的时隙而不是全部?
  2. 如何将检查的内容绑定到ngModel timeslotids属性?我是否需要在组件上创建一个数组属性并操纵它而不是依赖于ngModel? (试过这个,但显然没有做到这一点,所以回到下面的代码)
  3. 我似乎也遇到了一个绑定到一个简单的复选框(haselectric)的问题,因为它也没有在它应该的时候进行检查。我错过了一个能解决所有问题的导入吗?
  4. 代码解释 我有两个来自api的对象(设施和时间段),我绑定到接口。为简单起见,它们的性能已显着降低:

    export interface IFacility {   
       id: number,
       name: string,
       haselectric: boolean, 
       timeslotids: number[],    
       timeslots: ITimeslot[]
    
    }
    export interface ITimeslot {
        id: number,
        timeslotname: string    
    }
    

    这是Timeslots的JSON数据:

    [{"id":1,"timeslotname":"Daily"},{"id":2,"timeslotname":"Hourly"},{"id":4,"timeslotname":"Market"}]
    

    这是更新前单个工厂的JSON数据:

    {"id":2,"name":"Clements Building","haselectric":true,"timeslotids":[1],"timeslots":[{"id":1,"timeslotname":"Daily"}]}
    

    用于编辑设施的组件(facility.component.html):

    <form #form="ngForm" (ngSubmit)="submitForm()" *ngIf="formactive">
       <input type="hidden" [(ngModel)]="updatedfacility.id" #id="ngModel" name="id" />
        <div class="form-group">
             <label for="name">Facility Name *</label>
             <input type="text" class="form-control input-lg" [(ngModel)]="updatedfacility.name" #name="ngModel" name="name" placeholder="Facility Name *">
       </div>
       <div class="form-group">
                        <label for="exhibitspaces">Has Electric *</label>
                        <input type="checkbox" class="form-control input-lg" [(ngModel)]="updatedfacility.haselecric" #haselectric="ngModel" name="haselectric">
        </div>
        <div class="form-group">
            <label for="timeslots">Select Timeslots Available for Rent *</label>
            <div *ngIf="dbtimeslots" >
                <span *ngFor="let timeslot of dbtimeslots" class="checkbox">
                    <label for="timeslot">
                        <input type="checkbox" [(ngModel)]="updatedfacility.timeslotids" value="{{timeslot.id}}" name="{{timeslot.id}}" [checked]="updatedfacility.timeslotids.indexOf(timeslot.id)" />{{timeslot.timeslotname}}
                     </label>
                 </span>
            </div>
        </div>
        <button type="submit" class="btn btn-lg btn-default" [disabled]="form.invalid">Update</button> 
    </form>
    

    组件的代码(facility.component.ts)

    import { Component, OnInit, Input, Output, OnChanges, EventEmitter  } from '@angular/core';
    import { Observable } from 'rxjs/Observable';
    import { ActivatedRoute, Router } from '@angular/router'; 
    import { FormsModule }  from '@angular/forms';
    import { FacilityService }  from '../../../services/facility.service';
    import { TimeslotService } from '../../../services/timeslot.service';
    import { IFacility } from '../../../services/facility.interface';
    import { ITimeslot } from '../../../services/timeslot.interface';
    
    @Component({
       template: require('./facility.component.html')
    })
    export class FacilityDetailsComponent {
      facility: IFacility;
      httpresponse: string;
      successMessage: string;
      errormessage: string;
      showSuccess: boolean = true;
      showError: boolean = true;
      formactive: boolean = true;
      dbtimeslots: ITimeslot[];    
    
    
      constructor(
        private _route: ActivatedRoute,
        private _router: Router,
        private _facilityservice: FacilityService,
        private _timeslotservice: TimeslotService
      ) {}
    
      ngOnInit(): void {
        this._timeslotservice.getTimeslots().subscribe(timeslots => this.dbtimeslots = timeslots, error => this.errormessage = <any>error);
        let id = +this._route.snapshot.params['id'];
    
        this._facilityservice.getFacility(id)
            .subscribe(facility => this.facility = facility,
            error => this.errormessage = <any>error);
    
      }
    
      submitForm() {
        //update the facility through the service call
        this._facilityservice.updateFacility(this.facility)
            .subscribe(response => {
                this.httpresponse = response;
                console.log(this.httpresponse);
                this.successMessage = "Facility updated!";
                this.formactive = false;
                setTimeout(() => this.formactive = true, 3);
                this.showSuccess = false;
            },
            error => {
                this.errormessage = <any>error;
                this.showError = false;
            });
      }     
    

    }

    P.S。我在时间段的设施对象中有两个属性的原因是因为id的列表更容易传递给API进行更新。而不是传递完整的模型(时间段比我在这里更大,而不需要更新数据库)。请保留对此的评论,因为它与需要完成的工作无关。

    我发现了这个问题......但可悲的是,没有人回答这个可怜的家伙:ngmodel binding with dynamic array of checkbox in angular2 试过这个,但没有成功:Get values from a dynamic checkbox list 我还尝试了更新复选框的(更改)本地属性的版本,但似乎无效:Angular 2: Get Values of Multiple Checked Checkboxes

2 个答案:

答案 0 :(得分:12)

根据上面的НЛО回答,我能够找出问题的解决方案。谢谢НЛО。

<div class="form-group">
    <label for="timeslots">Select Timeslots Available for Rent *</label>
    <div *ngIf="dbtimeslots">
        <span *ngFor="let timeslot of dbtimeslots" class="checkbox">
            <label>
                <input type="checkbox" value="{{timeslot.id}}" name="{{timeslot.id}}"  [checked]="(facility.timeslotids && (-1 !== facility.timeslotids.indexOf(timeslot.id)) ? 'checked' : '')" (change) ="updateSelectedTimeslots($event)" />{{timeslot.timeslotname}}
            </label>
         </span>
    </div>
</div>

然后是组件上的函数:

updateSelectedTimeslots(event) {
    if (event.target.checked) {
          if (this.facility.timeslotids.indexOf(parseInt(event.target.name)) < 0) { 
                this.facility.timeslotids.push(parseInt(event.target.name));

          }
     } else {
           if (this.facility.timeslotids.indexOf(parseInt(event.target.name)) > -1) 
            {
                this.facility.timeslotids.splice(this.facility.timeslotids.indexOf(parseInt(event.target.name)), 1);              
            }
    }
     //console.log("TimeslotIDs: ", this.facility.timeslotids);    
}

答案 1 :(得分:11)

我有一个类似于你的代码(ngFor覆盖所有可能的复选框,其中一些应该被检查,更改将被保存在我们没有迭代的某些数据结构中),这里&#39我想出的是:

<md-checkbox 
    *ngFor="let some of availableSomes"
    name="{{ some }}"
    checked="{{ data.somes && -1 !== this.data.somes.indexOf(some) ? 'checked' : '' }}"
    (change)="updateSome($event)">
    {{ some }}
</md-checkbox>

此处updateSome

updateSome(event) {
  if (-1 !== this.availableSkills.indexOf(event.source.name)) {
    if (event.checked) {
      this.data.somes.push(event.source.name);
    } else {
      this.data.somes.splice(this.data.somes.indexOf(event.source.name), 1);
    }
  }
}

此外,我认为它应该是event.target,但由于材料的原因,它应该是event.source。有点笨拙的解决方案,但我认为它会帮助你弄清楚如何实现你想要的目标