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

Posted

技术标签:

【中文标题】将 ngModel 绑定到动态复选框列表:Angular 2 / Typescript【英文标题】:Binding ngModel to Dynamic Checkbox List : Angular 2 / Typescript 【发布时间】:2017-09-21 15:10:45 【问题描述】:

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

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

    如何解决此问题,以便仅检查设施数据中包含的时间段而不是全部? 如何将检查的内容绑定到 ngModel 时间段属性?我是否需要在组件上创建一个数组属性并对其进行操作而不是依赖于 ngModel? (试过了,但显然做得不对,所以回到下面的代码) 我似乎在绑定到一个简单的复选框 (haselectric) 时也遇到了问题,因为它也没有在应该检查的时候检查。我是否错过了可以解决所有这些问题的导入?

代码说明 我有两个对象(设施和时间段)来自我绑定到接口的 api。为简单起见,它们的属性已显着减少:

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


export interface ITimeslot 
    id: number,
    timeslotname: string    

这是时隙的 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;
        );
       

附:我在时隙的工具对象中有两个属性的原因是因为 id 列表更容易传递给 API 进行更新。而不是传递完整的模型(时隙比我这里的大,不需要更新数据库)。请保留 cmet,因为它与需要完成的事情无关。

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

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

我有一个类似的问题,我不知道我弄错了。如果你有时间看看***.com/questions/51867855/…【参考方案2】:

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

<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。有点笨拙的解决方案,但我认为它会帮助你弄清楚如何实现你想要的

【讨论】:

非常感谢。打算试试这个并回帖。 这为我指明了我需要的方向。我用解决方案代码更新了上面的原始帖子。非常感谢! @EHeine 很高兴你知道了。您应该已发布工作解决方案作为答案并接受它 哦,对不起。不要在这里多发帖。我会这样做的。 非常感谢,它帮助了我

以上是关于将 ngModel 绑定到动态复选框列表:Angular 2 / Typescript的主要内容,如果未能解决你的问题,请参考以下文章

*ngFor 中的 Angular 复选框

角垫复选框动态与ngModel

为啥表单标签会与我的 ngModel 和属性绑定混淆? ngModel 在 ngFor 里面 Form 标签

如何将复选框绑定到Angular7中的字符串值?

[(ngModel)] 和 [ngModel] 将状态绑定到属性的区别?

在由 AJAX 插入的动态创建元素上绑定事件(复选框)