简体   繁体   English

禁用 Angular 5 输入字段正确方法

[英]Disable Angular 5 Input fields correct way

I have a FormGroup that was created like that:我有一个这样创建的 FormGroup:

form: FormGroup;

constructor(private _formBuilder: FormBuilder) { }

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

When an event occurs I want to disable those inputs, so, in the HTML I added:当事件发生时,我想禁用这些输入,因此,在 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>

Where isDisabled is a variable I toggle to true when the said event happens.其中isDisabled是一个变量,我在所述事件发生时切换为true

As you can imagine, I get the message:你可以想象,我得到了这样的信息:

It looks like you're using the disabled attribute with a reactive form directive.看起来您正在将 disabled 属性与反应式表单指令一起使用。 If you set disabled to true when you set up this control in your component class, the disabled attribute will actually be set in the DOM for you.如果在组件 class 中设置此控件时将 disabled 设置为 true,则实际上将在 DOM 中为您设置 disabled 属性。 We recommend using this approach to avoid 'changed after checked' errors.我们建议使用这种方法来避免“检查后更改”错误。

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

So, with the example this warning shows and with a little search I found that I should declare my controls like:因此,通过此警告显示的示例并进行一些搜索,我发现我应该声明我的控件,例如:

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

The problem is: It is not toggling between disabled/enabled when the variable changes between true / false问题是:当变量在true / false之间变化时,它不会在禁用/启用之间切换

How is the correct way of having a variable controlling if an input is enabled or disabled?如果启用或禁用输入,如何控制变量的正确方法是什么?

I don't want to do it manually (ex: this.form.controls['name'].disable() ) because it doesn't seems a very reactive way, I would have to call it inside a good amount of methods.我不想手动执行(例如: this.form.controls['name'].disable() ),因为它似乎不是一种非常被动的方式,我必须在大量方法中调用它. Probably not a good practice.可能不是一个好习惯。

Thx谢谢

You can change the assignment of the variable to a setter method so that you'd have:您可以将变量的分配更改为 setter 方法,以便您拥有:

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

One solution is creating a directive and using binding for that as described in 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 ) {
  }

}

then然后

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

NOTE:笔记:

Doesn't work with Ivy不适用于常春藤

The proper way to disable an form control.禁用表单控件的正确方法。 With reactive forms you should never disable an input from the template.使用响应式表单,您永远不应该禁用模板中的输入。 So in whatever method in your component you are calling you should disable the input like this:因此,在您调用的组件中的任何方法中,您都应该像这样禁用输入:

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

Disable TextBox in Angular 7在 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>

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

You can use this code on your ts file.您可以在 ts 文件中使用此代码。

All controls:所有控件:

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

Some controls一些控件

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

Or Initial set method.或初始设置方法。

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

In Reactive Form you can disable all form fields by this.form.disable() .在反应式表单中,您可以通过this.form.disable()禁用所有表单字段。 In Template Driven Form you can disable all form fields by this.myform.form.disable() where myForm is @ViewChild('form') myForm ;在模板驱动表单中,您可以通过this.myform.form.disable()禁用所有表单字段,其中 myForm 为@ViewChild('form') myForm

Not the clean or dry'st I imagine.不是我想象的干净或干燥的。 Bu I tried the "set method" and didn't work out of the box...但是我尝试了“设置方法”并没有开箱即用......

Needed some refactoring () => {simpleVersion} (hope it helps someone)需要一些重构 () => {simpleVersion} (希望对某人有所帮助)

component.ts组件.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;
    }
   }

& perhaps overkill on the HTML logic, so hope you find the bonus integrated ngClass toggle just as helpful.并且可能在 HTML 逻辑上矫枉过正,所以希望您发现额外的集成 ngClass 切换同样有帮助。

component.html (toggle button) component.html(切换按钮)

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

The solution by creating a directive and using binding for that worked for me in Angular 10 is described in hereAngular 10中创建directive并使用binding为我工作的解决方案在此处描述

Template:模板:

<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) {}
}

I have a function that enables a control on click.我有一个功能可以控制点击。

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

Originally i was using最初我正在使用

  control.disabled = false;

But this did not work for controls with <input> for example in my mat-chip-list .但这不适用于带有<input>的控件,例如在我的mat-chip-list

I use FormGroup and disable each control in the constructor我使用 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>

As control can't be accessed in reactive forms .由于无法以反应形式访问控件。 This is due to migration to Ivy .这是由于迁移到Ivy所致。 You can use can access the html attribute directly and specify your condition.您可以使用 can 直接访问 html 属性并指定您的条件。 See this issue #35330 for more details and alternative methods.有关更多详细信息和替代方法,请参阅此问题#35330

[attr.disabled]="true || false"

You can create set and get method to achieve conditionally enable/disable functionality for Angular material Reactive Forms:您可以创建 set 和 get 方法来实现有条件地启用/禁用 Angular 材料反应形式的功能:

*// 1st Step: *// 第一步:

 set isDisabled(value:boolean) {
      if(value){
       this.form.controls['Form controller name'].disable(); //you can keep empty if you don't add controller name

      } 
      else{
       this.form.controls['Form controller name'].enable();
      }
    }

// 2nd Step: Add conditions in getter // 第二步:在getter中添加条件

get isDisabled(){
  return condition ? true : false;
}

// 3rd Step // 第三步

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

Remove [disabled]="isDisabled" from input fields and add ng-disabled="all" and in the event field add ng-model="all"从输入字段中删除 [disabled]="isDisabled" 并添加 ng-disabled="all" 并在事件字段中添加 ng-model="all"

<body ng-app="">
Click here to disable all the form fields:<input type="checkbox" ng-model="all">


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

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

</body>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM