Отключить поля ввода Angular 5 правильно

У меня есть 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, когда происходит указанное событие. Как вы понимаете, я получаю сообщение:

It looks like you're using the disabled attribute with a reactive form directive. 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. 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)
  });

Итак, в примере, показанном в этом предупреждении, и с небольшим поиском я обнаружил, что должен объявить свои элементы управления следующим образом:

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

Проблема такая: Он не переключается между отключенным / включенным, когда переменная изменяется между true / false.

Как правильно управлять переменной, если вход включен или отключен?

Я не хочу делать это вручную (например, this.form.controls['name'].disable()), потому что это не кажется очень реактивным способом, мне пришлось бы вызывать его внутри большого количества методов. Наверное, это не лучшая практика.

Спасибо

Я использую (change) = "" в сочетании с [(ngModel)], работает как чары, также проверяю это SO post довольно круто ИМХО

BSchnitzel 07.05.2018 20:59

кстати, вам не нужны оба formControlName = "name" [(ngModel)] = "name" на ваших входах

Reza 07.05.2018 21:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
37
2
119 019
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Одним из решений является создание директивы и использование для нее привязки, как описано в здесь.

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 13.03.2020 11:04

@jurekskowron спасибо за внимание, стоит опубликовать рабочий пример в качестве ответа

Reza 13.03.2020 14:52

Спасибо @jurekskowron. Упомянутое решение сработало для меня в Angular 10. Я опубликовал то же самое, что и новый ответ.

Roy 10.02.2021 13:10

Правильный способ отключить элемент управления формой. С реактивными формами вы никогда не должны отключать ввод из шаблона. Итак, в любом методе вашего компонента, который вы вызываете, вы должны отключить ввод следующим образом:

this.form.get('name').disable();
Ответ принят как подходящий

Вы можете изменить присвоение переменной методу установки, чтобы у вас было:

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

Почему это правильный ответ? Это больше похоже на Kludge, чем на решение.

jwize 11.01.2020 08:31

Большое спасибо, его работа

Mahdi 03.02.2021 07:46

Для ввода используйте [readonly], а не [disabled], и он будет работать

Да, сработает, но атрибуты readonly и disabled действительно имеют разное значение.

Roman Šimík 13.04.2019 21:35

В реактивной форме вы можете отключить все поля формы с помощью this.form.disable(). В форме, управляемой шаблоном, вы можете отключить все поля формы с помощью this.myform.form.disable(), где myForm - @ViewChild('form') myForm;

Не самое чистое или сухое, как мне кажется. Но попробовал "метод набора" и из коробки не вышло ...

Требуется некоторый рефакторинг () => {simpleVersion} (надеюсь, это кому-то поможет)

component.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>

Отключить TextBox в 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>

У меня есть функция, которая позволяет управлять нажатием.

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

Первоначально я использовал

  control.disabled = false;

Но это не сработало для элементов управления с <input>, например, в моем 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>

Вы можете использовать этот код в своем 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), как я пытался. Вы должны указать ключ (значение) для значения.

Sky 13.08.2020 05:29

Решение путем создания directive и использования binding, которое сработало для меня в Angular 10, описано в здесь.

Шаблон:

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

Машинопись:

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?

Gabor 16.02.2021 22:33

Другие вопросы по теме