Подтвердить что ты не робот

Как изменить HTML-элемент readonly и требуемый атрибут в Angular2 Typescript?

Для некоторых моих компонентов я хотел бы изменить исходное поле readonly и необходимые атрибуты взад и вперед.

Мне удалось получить исполняемый код, который изменяет оба из них по требованию, но проблема в том, что он работает только для чтения, но, похоже, не работает над требуемым: хотя атрибут элемента изменяется на требуемый Angular2, все еще думает fieldCtrl действителен.

Вот мой плункер, где я проиллюстрировал эту проблему: https://plnkr.co/edit/Yq2RDzUJjLPgReIgSBAO?p=preview

//our root app component
import {Component} from 'angular2/core'

@Component({
  selector: 'my-app',
  providers: [],
  template: `
    <div>
    <form #f="ngForm">
      <button type="button" (click)="toggleReadOnly()">Change readonly!</button>
      <button type="button" (click)="toggleRequired()">Change required!</button>
      <input id="field" [(ngModel)]="field" ngControl="fieldCtrl" #fieldCtrl="ngForm"/>
      {{fieldCtrl.valid}}
    </form>
    </div>
  `,
  directives: []
})
export class App {
  constructor() {
    this.name = 'Angular2'
  }

  toggleRequired(){
    this.isRequired = !this.isRequired;
    var fieldElement = <HTMLInputElement>document.getElementById('field');
    if (this.isRequired){
      fieldElement.required = true;
      this.field = "it required now";
    }
    else{
      fieldElement.required = false;
      this.field = "can leave it blank";
    }
  }

  toggleReadOnly(){
    this.isReadOnly = !this.isReadOnly;
    var fieldElement = <HTMLInputElement>document.getElementById('field');
    if (this.isReadOnly){
      fieldElement.readOnly = true;
      this.field = "it readonly now";
    }
    else{
      fieldElement.readOnly = false;
      this.field = "feel free to edit";
    }
  }

  private isReadOnly:boolean=false;

  private field:string = "feel free to edit";

  private isRequired:boolean=false;

}

UPDATE: Пробовал предложенный метод

[required]="isRequired" [readonly]="isReadOnly"

И он работает как прелесть для readonly и для required = true, но я больше не могу отключить требуемый атрибут - он показывает, что пустое поле недопустимо, хотя и не требуется больше.

Обновлено плункер: https://plnkr.co/edit/6LvMqFzXHaLlV8fHbdOE

UPDATE2: Пробовал предложенный метод

[required]="isRequired ? true : null"

Он добавляет/удаляет требуемый атрибут из элемента по запросу, однако свойство допустимого полевого контроллера показывает false для пустого поля, которое не требуется.

Каким будет правильный способ изменения требуемого атрибута в Angular2 Typescript?

4b9b3361

Ответ 1

Чтобы связать атрибуты, которые нужно удалить, их нужно установить равными нулю. Было обсуждение, чтобы изменить его, чтобы удалить по ложному, но он был отклонен, по крайней мере на данный момент.

 [required]="isRequired ? '' : null"

или

 [required]="isRequired ? 'required' : null"

Ваш Plunker выдает ошибку из-за отсутствия [] вокруг ngControl.

См. также Plunker для рабочего примера

См. также комментарии Дейлана ниже.

Ответ 2

Кажется, у вас уже есть ответ для добавления/удаления атрибута readonly. Для требуемого атрибута я предлагаю создать службу, чтобы отслеживать состояние включенного/отключенного валидатора, а затем использовать службу при привязке к вашим элементам проверки.

Проверка состояния

Этот класс отвечает за отслеживание валидатора и его состояние включения/отключения.

export class StateValidator {
    public enabled: boolean = true;
    validator: (control: Control) => { [key: string]: boolean };
    constructor(validator: (control: Control) => 
        { [key: string]: boolean }, enabled: boolean) {
        this.enabled = enabled;
        this.validator = validator;

    }

    enable() {
        this.enabled = true;
    }
    disable() {
        this.enabled = false;
    }
    toggle() {
        this.enabled = !this.enabled;
    }
    get() {
        return (control: Control) => {
            if (this.enabled)
                return this.validator(control);
            return null;
        }
    }
}

Он имеет методы для включения, отключения или переключения проверки подлинности; а также метод get, который возвращает новую функцию валидатора, которая при вызове вызовет базовую функцию валидатора, если валидатор включен или возвращает значение null, когда валидатор не включен.

Служба валидации

Этот класс является однопользовательской службой, ответственной за регистрацию валидаторов по ключу и поддерживающих методы для включения, отключения или переключения проверки на основе этого ключа.

export class ValidationService {
    validators: { [key: string]: StateValidator } = {};
    register(key: string, validator: Function): Function {
        var stateValidator = new StateValidator(<(control: Control) => { [key: string]: boolean }>validator, true);
        this.validators[key] = stateValidator;
        return stateValidator.get();
    }
    enable(key: string) {
        this.validators[key].enable();
    }
    disable(key: string) {
        this.validators[key].disable();
    }
    toggle(key: string) {
        this.validators[key].toggle();
    }
    list() {
        var l = [];
        for (var key in this.validators) {
            if (this.validators.hasOwnProperty(key)) {
                l.push({ key: key, value: this.validators[key].enabled });
            }
        }
        return l;
    }
}

У службы также есть функция list для возврата списка пар ключ/значение, где ключ представляет зарегистрированный ключ проверки, а значение является логическим индикатором, который представляет состояние включенного проверки.

Компонент

Чтобы использовать ValidationService, зарегистрируйте службу с инжектором корня во время начальной загрузки:

bootstrap(AppComponent, [ValidationService]);

Или зарегистрируйте службу с помощью инжектора на уровне компонента:

@Component({
  selector: 'app',
  providers: [ValidationService],
  ...
})

Затем введите службу в свой конструктор компонента:

export class AppComponent {
    form: ControlGroup;
    constructor(public validationService:ValidationService) {
      ...
    }
}

Затем привяжите к элементам проверки, как обычно, за исключением использования ValidationService для регистрации и возврата проверки состояния:

new Control('', validationService.register('required', Validators.required));

Одна из замечательных особенностей этого решения заключается в том, что вы можете легко создавать и смешивать проверки состояния с другими встроенными или настраиваемыми валидаторами:

this.form = new ControlGroup({
    name: new Control('hello',
        Validators.compose([
            validationService.register('required', Validators.required),
            validationService.register('minlength', Validators.minLength(4)),
            Validators.maxLength(10)]))

});

Переключение валидатора

Используйте службу для переключения состояния проверки:

validationService.toggle('required');

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

<table>
  <tr>
     <td>Validator</td>
     <td>Is Enabled?</td>
     <td></td>
  </tr>
  <tr *ngFor="#v of validationService.list()">
     <td>{{v.key}}</td>
     <td>{{v.value }}</td>
     <td><button (click)="validationService.toggle(v.key)">Toggle</button></td>
  </tr>
</table>

Демо Plnkr

введите описание изображения здесь

Ответ 3

Альтернативное решение, которое я использую:

import {Directive, ElementRef, Input} from '@angular/core';

@Directive({
    selector: '[symToggleRequired]'
})
export class ToggleRequiredDirective {
    @Input() public set symToggleRequired(condition: boolean) {
        if (condition) {
            (<HTMLElement>this.element.nativeElement).setAttribute('required', 'true');
        } else {
            (<HTMLElement>this.element.nativeElement).removeAttribute("required");
        }
    } 

    constructor(
        private element: ElementRef
    ) { } 
}

Используйте эту директиву для элемента html для удаления или добавления требуемого атрибута:

<input [symToggleRequired]='FlagPropertyOfYourComponent'>