将 ngModel 绑定到动态复选框列表:Angular 2 / Typescript
Binding ngModel to Dynamic Checkbox List : Angular 2 / Typescript
我不确定绑定和更新动态生成复选框的模型的正确方法。 (这是一个 ASP.NET 核心项目 Angular 2 最初是使用 Yeoman 生成器创建的)或者我刚刚发现的一个简单的复选框。
以下是精简代码,其中包含设施和时隙。每个设施可以有多个时隙。时隙复选框列表显示正常。初始数据表明只应检查一个时隙。但是当我加载一个设施时,所有的时间段都会被检查。它们没有像我预期的那样与 ngModel 绑定。
- 如何修复它以便只检查设施数据中包含的时隙而不是全部?
- 如何将检查的内容绑定到 ngModel timeslotids 属性?我是否需要在组件上创建一个数组 属性 并对其进行操作而不是依赖 ngModel? (试过这个但显然没有做对所以恢复到下面的代码)
- 我似乎也遇到了绑定到一个简单的复选框(有电)的问题,因为它也没有在应该的时候勾选。我是否缺少可以解决所有这些问题的导入?
代码说明
我有两个对象(设施和时隙)来自我绑定到接口的 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;
});
}
}
P.S。我在时隙的设施对象中有两个属性的原因是因为 id 列表更容易传递给 API 进行更新。而不是传递完整的模型(时隙比我这里的要大,不需要更新数据库)。请保留对此的评论,因为它与需要完成的工作无关。
我发现了这个问题...但遗憾的是,没有人回答这个可怜的家伙:ngmodel binding with dynamic array of checkbox in angular2
试过这个但没有用:
我还尝试了在复选框的(更改)上更新本地 属性 的版本,但这似乎也不起作用:
我有一个类似于你的代码(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
,但由于 material,它是 event.source
。有点笨拙的解决方案,但我认为它会帮助您弄清楚如何实现您想要的
根据上面的 НЛО 回答,我找到了问题的解决方案。谢谢НЛО。
<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);
}
我不确定绑定和更新动态生成复选框的模型的正确方法。 (这是一个 ASP.NET 核心项目 Angular 2 最初是使用 Yeoman 生成器创建的)或者我刚刚发现的一个简单的复选框。
以下是精简代码,其中包含设施和时隙。每个设施可以有多个时隙。时隙复选框列表显示正常。初始数据表明只应检查一个时隙。但是当我加载一个设施时,所有的时间段都会被检查。它们没有像我预期的那样与 ngModel 绑定。
- 如何修复它以便只检查设施数据中包含的时隙而不是全部?
- 如何将检查的内容绑定到 ngModel timeslotids 属性?我是否需要在组件上创建一个数组 属性 并对其进行操作而不是依赖 ngModel? (试过这个但显然没有做对所以恢复到下面的代码)
- 我似乎也遇到了绑定到一个简单的复选框(有电)的问题,因为它也没有在应该的时候勾选。我是否缺少可以解决所有这些问题的导入?
代码说明 我有两个对象(设施和时隙)来自我绑定到接口的 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;
});
}
}
P.S。我在时隙的设施对象中有两个属性的原因是因为 id 列表更容易传递给 API 进行更新。而不是传递完整的模型(时隙比我这里的要大,不需要更新数据库)。请保留对此的评论,因为它与需要完成的工作无关。
我发现了这个问题...但遗憾的是,没有人回答这个可怜的家伙:ngmodel binding with dynamic array of checkbox in angular2
试过这个但没有用:
我有一个类似于你的代码(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
,但由于 material,它是 event.source
。有点笨拙的解决方案,但我认为它会帮助您弄清楚如何实现您想要的
根据上面的 НЛО 回答,我找到了问题的解决方案。谢谢НЛО。
<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);
}