У меня есть 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()), потому что это не кажется очень реактивным способом, мне пришлось бы вызывать его внутри большого количества методов. Наверное, это не лучшая практика.
Спасибо
кстати, вам не нужны оба formControlName = "name" [(ngModel)] = "name" на ваших входах



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Одним из решений является создание директивы и использование для нее привязки, как описано в здесь.
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. Я опубликовал то же самое, что и новый ответ.
Правильный способ отключить элемент управления формой. С реактивными формами вы никогда не должны отключать ввод из шаблона. Итак, в любом методе вашего компонента, который вы вызываете, вы должны отключить ввод следующим образом:
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, чем на решение.
Большое спасибо, его работа
Для ввода используйте [readonly], а не [disabled], и он будет работать
Да, сработает, но атрибуты readonly и disabled действительно имеют разное значение.
В реактивной форме вы можете отключить все поля формы с помощью 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), как я пытался. Вы должны указать ключ (значение) для значения.
Решение путем создания 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?
Я использую (change) = "" в сочетании с [(ngModel)], работает как чары, также проверяю это SO post довольно круто ИМХО