ngModel 不适用于 ngFor 中的输入类型复选框

Posted

技术标签:

【中文标题】ngModel 不适用于 ngFor 中的输入类型复选框【英文标题】:ngModal not working for input type checkbox inside ngFor 【发布时间】:2019-06-12 11:46:34 【问题描述】:

在 ngFor 中使用复选框时,ngModal 似乎不起作用,而 重复一个对象数组,如

["checked":true,"checked":false]

如果我们将组件中的 checked 属性更改为 true 或 false,它不会反映在 UI 中,同样的逻辑将适用于 md bootstrap 的 mdb-checkbox。

app.component.ts

import  Component  from '@angular/core';

@Component(
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
)
export class AppComponent  
  sampleObj = [
    'checked': false, name: 'option 1',
    'checked': false, name: 'option 2',
    'checked': false, name: 'option 3',
    'checked': true, name: 'option 4'
  ];

  sampleFunc(event, i) 
    if (event.currentTarget.checked) 
      alert(i);
      this.sampleObj[i].checked = false;
    
  

app.component.html

  <div *ngFor="let item of sampleObj; let i = index">
  <input type='checkbox' name='itemi' [(ngModel)]="item.checked" (change)="sampleFunc($event, i)" /> 
  <label for='itemi'><span>item.name</span></label>

</div>

工作示例 https://stackblitz.com/edit/angular-3orv4w

角度版本:

   Angular CLI: 7.1.1
Node: 10.14.2
OS: win32 x64
Angular: 7.1.1
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, language-service, material, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.11.1
@angular-devkit/build-angular     0.12.1
@angular-devkit/build-optimizer   0.12.1
@angular-devkit/build-webpack     0.12.1
@angular-devkit/core              7.1.1
@angular-devkit/schematics        7.1.1
@angular/pwa                      0.11.2
@angular/service-worker           7.1.2
@ngtools/webpack                  7.2.1
@schematics/angular               7.1.1
@schematics/update                0.11.1
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.23.1

【问题讨论】:

不清楚你在问什么。我使用了你的 stackblitz-Demo 并且它有效?!请更准确地说明您期望的行为。 @Lynx242 我的意思是基于 sampleObj 的选中属性,复选框应该可以工作。即来自组件,如果我们将已选中的属性更改为 true 以假设 sampleObj[2],UI 中的第三个复选框应该将其状态更改为 true 对吗?因为使用了 ngModel。 抱歉耽搁了,我有一些约会。请在下面找到我的解决方案。 【参考方案1】:

好的,我有一个解决方案。显然,Angular 内部并未将检查状态视为布尔值。

我做了以下事情:

我在您的 HTML 文件中添加了一个按钮,就在结束标记 &lt;/div&gt; 之后。仅用于测试目的。

<button (click)="toggle()">click me</button>

在 TypeScript-File 中,我添加了一个带有以下内容的切换方法。

toggle(): void 
    this.sampleObj[1].checked = !this.sampleObj[1].checked; 

这就是诀窍。

【讨论】:

感谢 Lynx,您的解决方案有效,但它仍然无法在 ngModelChange 中运行,也无法更改事件处理程序。如果我们更改 this.sampleObj[1].checked = !this.sampleObj[1].checked;它不会反映。 对不起,你有点失去我了。每当您单击这些复选框之一时,都会调用您的 sampleFunc()。但我不明白你为什么要在它们刚刚被检查时将它们重置为未选中?这背后的策略/用例是什么? PS:当(change) 触发时,您无法切换状态,因为此时您处于ngOnChanges()-hook 中。 Angular 不接受将值切换回此特定状态。 angular.io/guide/lifecycle-hooks 有什么办法可以实现吗?我能够使用 mdb-bootstrap 在更改事件中工作,但是对于典型的输入元素,它不起作用。【参考方案2】:

好的,就这样吧。这是你的 stackblitz-class 修改和评论。

为了达到你的目标,你可以做的是暂时记住当前点击的复选框的索引。我用变量marker 做到了这一点。

我几乎不建议在您开始操作该框之前等待ngAfterViewChecked()-hook,因为这样您可以确保在页面变慢时不会出现任何时间问题。

下一步是检查是否设置了标记。然后你必须将你的实际切换回代码包装到一个超时函数中。如果你不这样做,你会遇到这个错误:

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。以前的值:“模型:真”。当前值:'model: false'。

就是这样。

您可以尝试进一步减少超时,以使复选框甚至不闪烁。但请始终注意,如果您行动过快,可能会遇到上述错误。

import  Component  from '@angular/core';

@Component(
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
)
export class AppComponent  

  // the clicked checkbox's index
  private marker: number = -1;

  sampleObj = [
    'checked': false, name: 'option 1',
    'checked': false, name: 'option 2',
    'checked': false, name: 'option 3',
    'checked': true, name: 'option 4'
  ];

  sampleFunc(event, i) 
    if (event.currentTarget.checked) 
      // memorize the clicked checkbox's index
      this.marker = i;
    
  

  toggle() : void 
    this.sampleObj[1].checked = !this.sampleObj[1].checked; 
  

  ngAfterViewChecked(): void 
    // if a marker is set
    if (this.marker > -1) 
      // start the timeout and then reset the checkbox
      setTimeout (() => 
      this.sampleObj[this.marker].checked = !this.sampleObj[this.marker].checked;
      this.marker = -1;
      , 20);
    
  

【讨论】:

希望这会有所帮助。如果它解决了您的问题,请不要忘记将此答案标记为解决方案。 别提了。 ;o)

以上是关于ngModel 不适用于 ngFor 中的输入类型复选框的主要内容,如果未能解决你的问题,请参考以下文章

ngFor内的Angular2 ngModel

*ngFor 如何使用索引将数组中的每个项目绑定到 ngModel

Angular2,Ionic2:如何使用 ngModel 对嵌套 *ngfor 中的单选按钮进行 2way 绑定?

离子切换检查不适用于 ngModel ionic 3

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

用[(NgModel)]更改绑定的Angular表中的值会影响其他字段