【问题标题】:Disable Angular 5 Input fields correct way正确禁用 Angular 5 输入字段
【发布时间】:2018-10-17 15:21:27
【问题描述】:

我有一个这样创建的 FormGroup:

form: FormGroup;

constructor(private _formBuilder: FormBuilder) { }

this.form = this._formBuilder.group({
  name: ['', Validators.required],
  email: ['', Validators.required, Validators.email]
});

当事件发生时,我想禁用这些输入,因此,在我添加的 HTML 中:

<input class="form-control" placeholder="Name" name="name" formControlName="name" [(ngModel)]="name" autocomplete="off" [disabled]="isDisabled" required>

<input class="form-control" placeholder="Email" name="email" formControlName="email" [(ngModel)]="email" email="true" autocomplete="off" [disabled]="isDisabled" required>

其中isDisabled 是一个变量,当所述事件发生时我切换到true

正如你可以想象的那样,我收到了这样的信息:

您似乎正在使用带有反应形式的 disabled 属性 指示。如果将 disabled 设置为 true 当您在组件类中设置此控件时,disabled 属性实际上将在 DOM 中设置为 你。我们建议使用这种方法来避免“检查后更改”错误。

  Example: 
  form = new FormGroup({
    first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
    last: new FormControl('Drew', Validators.required)
  });

因此,通过此警告显示的示例并稍作搜索,我发现我应该声明我的控件,例如:

name: [{ value: '', disabled: this.isDisabled }, Validators.required]

问题是:当变量在true/false之间变化时,它不会在禁用/启用之间切换

如果启用或禁用输入,使用变量控制的正确方法是什么?

我不想手动执行(例如:this.form.controls['name'].disable()),因为它似乎不是一种非常被动的方式,我必须在大量方法中调用它。可能不是一个好习惯。

谢谢

【问题讨论】:

  • 我将 (change)="" 与 [(ngModel)] 结合使用就像一个魅力也检查 this 所以发布非常棒的恕我直言
  • 顺便说一句,你的输入不需要formControlName="name" [(ngModel)]="name"

标签: javascript html angular angular-forms


【解决方案1】:

您可以将变量的赋值更改为 setter 方法,以便您拥有:

set isDisabled(value: boolean) {
 this._isDisabled = value;
 if(value) {
  this.form.controls['name'].disable();
 } else {
    this.form.controls['name'].enable();
  }
}

【讨论】:

  • 为什么这是正确答案?这看起来更像是 Kludge,而不是解决方案。
  • 这不是一个好办法,因为用户可以通过浏览器删除这个属性,这样模型中的数据会发生变化吗?例如,我有一个保存用户信息的表单,我做了一个添加禁用属性的一些字段,我想在保存表单时排除禁用的属性。
【解决方案2】:

一种解决方案是创建一个指令并使用 here 中所述的绑定

import { NgControl } from '@angular/forms';

@Directive({
  selector: '[disableControl]'
})
export class DisableControlDirective {

  @Input() set disableControl( condition : boolean ) {
    const action = condition ? 'disable' : 'enable';
    this.ngControl.control[action]();
  }

  constructor( private ngControl : NgControl ) {
  }

}

然后

<input class="form-control" placeholder="Name" name="name" formControlName="name" autocomplete="off" [disableControl]="isDisabled" required>

注意:

不适用于常春藤

【讨论】:

  • 在 Ivy 中(自 Angular 9 起默认)有一个错误“注入的 ngControl 不包含控件属性”(在 Ivy 之前没问题)。我在这里找到了解决方案(虽然看起来很尴尬):github.com/angular/angular/issues/35330
  • @jurekskowron 感谢您的提醒,值得将您的工作示例发布为答案
  • 谢谢@jurekskowron。提到的解决方案在 Angular 10 中对我有用。我发布了与新答案相同的内容。
【解决方案3】:

在 Angular 7 中禁用文本框

<div class="center-content tp-spce-hdr">
  <div class="container">
    <div class="row mx-0 mt-4">
      <div class="col-12" style="padding-right: 700px;" >
          <div class="form-group">
              <label>Email</label>
                <input [disabled]="true" type="text" id="email" name="email" 
                [(ngModel)]="email" class="form-control">
          </div>
     </div>
   </div>
 </div>

【讨论】:

    【解决方案4】:

    禁用表单控件的正确方法。使用响应式表单,您永远不应该禁用模板中的输入。因此,在您调用的组件中的任何方法中,您都应该像这样禁用输入:

    this.form.get('name').disable();
    

    【讨论】:

      【解决方案5】:

      对于输入使用 [readonly] 而不是 [disabled] 它会起作用

      【讨论】:

      • 是的,它会起作用,但是属性readonlydisabled 的含义真的不同。
      【解决方案6】:

      在响应式表单中,您可以通过 this.form.disable() 禁用所有表单字段。 在模板驱动表单中,您可以通过 this.myform.form.disable() 禁用所有表单字段,其中 myForm 为 @ViewChild('form') myForm

      【讨论】:

        【解决方案7】:

        您可以在您的 ts 文件中使用此代码。

        所有控件:

        this.form.disable()
        this.form.enable()
        

        一些控件

        this.form.get('first').disable()
        this.form.get('first').enable()
        

        或初始设置方法。

        first: new FormControl({value: '', disabled: true}, Validators.required)
        

        【讨论】:

        • 对于初始设置方法,我尝试过应该是first: new FormControl({value: '', disabled: true}, Validators.required)。您必须为值指定键(值)。
        【解决方案8】:

        不是我想象的干净或干燥的。但是我尝试了“设置方法”并没有开箱即用......

        需要一些重构 () => {simpleVersion}(希望对某人有所帮助)

        组件.ts

        ...
          // standard stuff...
          form: FormGroup;
          isEditing = false;
        ...
          // build the form...
          buildForm() {
            this.form = this.FormBuilder.group({
              key: [{value:'locked', disabled: !this.isEditing}],
              name: [],
              item: [],
              active: [false]
            })
          }
          // map the controls to "this" object
          // => i.e. now you can refer to the controls directly (ex. this.yourControlName)
          get key() { return <FormControl>this.form.get('key') }
          get name() { return <FormControl>this.form.get('name') }
        ...
          // ----------------------------------------
          //     THE GRAND FINALÉ - disable entire form or individual controls
          // ----------------------------------------
          toggleEdit() {
            if(!this.isEditing) {
              this.key.enable();      // controls
              this.name.enable();
              // this.form.enable();     // the form
        
              this.isEditing = !this.isEditing;
            } else {
              this.key.disable();      // the controls
              this.name.disable();     // the controls
        
              // this.form.disable();     // or the entire form
        
              this.isEditing = !this.isEditing;
            }
           }
        
        

        & 可能在 HTML 逻辑上有点矫枉过正,所以希望您发现额外的集成 ngClass 切换同样有帮助。

        component.html(切换按钮)

        <div class="btn-group" (click)="toggleEdit()">
                   <label
                     class="btn"
                     role="button"
                     [ngClass]="{'btn-success': isEditing,
                                 'btn-warning': !isEditing}">toggle edit
                   </label>
        </div>
        

        【讨论】:

          【解决方案9】:

          Angular 10 中创建directive 并使用binding 为我工作的解决方案在here 中进行了描述

          模板:

          <mat-form-field>
          <input matInput class="form-control" formControlName="NameText" [disableControl]="condition" type="text">
          </mat-form-field>
          

          TypeScript:

          import { Directive, Input } from '@angular/core';
          import { NgControl } from '@angular/forms';
          
          @Directive({
            selector: '[opDisabled]'
          })
          export class DisabledDirective {
            @Input()
            set opDisabled(condition: boolean) {
              const action = condition ? 'disable' : 'enable';
              setTimeout(() => this.ngControl.control[action]());
            }
          
            constructor(private ngControl: NgControl) {}
          }
          

          【讨论】:

          • 我在指令中使用 element.nativeElment 并使用 setTimeout 解决了我的问题。但我不知道为什么 setTimeout 在这种情况下会有所帮助?
          【解决方案10】:

          我有一个启用点击控件的功能。

            controlClick(control: any) {
                this.form.controls[control.ngControl.name].enable();
            }
          

          原来我用的是

            control.disabled = false;
          

          但这不适用于带有&lt;input&gt; 的控件,例如在我的mat-chip-list 中。

          我使用 FormGroup 并禁用构造函数中的每个控件

            constructor(
              private fb: FormBuilder,
              private dialogRef: MatDialogRef<EditDialogComponent>,
              @Inject(MAT_DIALOG_DATA) data
            ) {
              this.data = data;
              this.multiEdit = data.multiSelect;
          
              this.form = new FormGroup({
                autoArchive: new FormControl({
                  value:
                    this.getPreFill(data.selectedPolicy.autoArchive, this.multiEdit),
                  disabled: true
                  /*, Validators.required*/
                }),
          

          ...

            <mat-form-field (click)="controlClick(retrieveChipList)">
                <mat-chip-list #retrieveChipList formControlName="retrieveChipList">
                  <mat-chip
                  *ngFor="let email of data.selectedPolicy.retrieveEmailsToBeNotified" 
                    (removed)="remove(email)" [selectable]="selectable"
                    [removable]="removable" 
                  >
                    {{ email }}
                    <mat-icon matChipRemove>cancel</mat-icon>
                  </mat-chip>
                  <input
                  placeholder="Retrieve Emails to be Notified" 
                  formControlName="retrieveChipList"
                    [matChipInputFor]="retrieveChipList"
                    [matChipInputAddOnBlur]="true"
                    [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
                    (matChipInputTokenEnd)="addRetrieveEmails($event)"
                  />
                </mat-chip-list>
              </mat-form-field>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-06-28
            • 1970-01-01
            • 1970-01-01
            • 2016-03-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多