Angular 2 сохраняет значение входной формы в привязке к модели, используя геттер и сеттер

Я хотел бы привязать входное значение к модели, используя геттеры и сеттеры. Таким образом, я могу предотвратить и/или манипулировать значением ввода при записи внутри него.

Например, я хочу, чтобы номера предотвращения находились внутри поля ввода. Итак, если написать «abc», все в порядке, тогда, если я начну писать число, ничего не должно произойти (с моделью и значением ввода). Проблема в том, что с помощью следующего кода я могу написать что-нибудь в поле ввода (но модель правильная). Это означает, что значение поля ввода на самом деле не представляет мою модель.

ПРИМЕЧАНИЕ. Причина, выходящая за рамки этих вопросов, заключается в том, что я хочу использовать свои модели для проверки форм, предотвращая, например, определенные символы. Я бы не хотел использовать реактивные формы, так как я хочу, чтобы мои проверки оставались внутри моих моделей, а не компонентов. Также обратите внимание, что в реальном сценарии у меня был бы класс UserModel с внутренним именем и другими полями с их проверками. .

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2><input type="text" [(ngModel)]="name"> {{name}}</h2>
    </div>
  `,
})
export class App {
  _name:string = 'ss';
  constructor() {
  }

  // In real scenario those 2 methods are in a separate class UserModel
  get name() {
    return this._name;
  }

  set name() {
    if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
        this._name = val;
    }
  }
}

person Marco Turi    schedule 17.03.2017    source источник
comment
в чем проблема?   -  person Suraj Rao    schedule 17.03.2017
comment
Я обновил вопрос, надеюсь, теперь это более понятно.   -  person Marco Turi    schedule 17.03.2017
comment
Пожалуйста, приведите конкретный пример того, что вы хотите. То, что вы не хотите, не слишком полезно ;-) Итак, если this._name содержит значение abc и пользователь вводит 123, но вы не хотите разрешать числа, что именно должно произойти?   -  person Günter Zöchbauer    schedule 17.03.2017
comment
ничего, входное значение должно сохранять abc. (я добавляю лучший пример в вопрос)   -  person Marco Turi    schedule 17.03.2017


Ответы (3)


Если вы манипулируете значением в установщике, это может вызвать проблемы с обнаружением изменений, так что ngModel не улавливает изменения и не обновляет <input>

Чтобы обойти вы можете использовать

export class App {

  _name:string = 'ss';

  constructor(private cdRef:ChangeDetectorRef) {}

  get name() {
    return this._name;
  }

  set name(value:String) {
    this._name = value + 'x';
    this.cdRef.detectChanges()
  }
}

если вы сбрасываете значение на предыдущее значение, вам может потребоваться сначала передать искусственное другое значение, иначе обнаружение изменений не обнаружит изменение, и даже detectChanges() не обновит ввод.

  set name(value:String) {
    var oldVal = this._name;
    this._name = null;
    this.cdRef.detectChanges()
    this._name = oldVal;
    this.cdRef.detectChanges()
  }
person Günter Zöchbauer    schedule 17.03.2017
comment
Это работает, но это действительно сложно. Я бы не хотел, чтобы во всей моей модели были обнаружены изменения. - person Marco Turi; 17.03.2017
comment
Я не знаю лучшего способа. - person Günter Zöchbauer; 17.03.2017
comment
из моего тестирования необходимо сначала изменить значение, как описано выше. - person Tom Doe; 21.06.2017

Основываясь на ответе @Günter Zöchbauer, я нашел обходной путь. Это не окончательно и может быть более абстрактно, но пока все в порядке.

export class App implements OnInit {
    @Input() userModel: UserModel = null;
    public _vm;

    constructor(private _changeDetectionRef: ChangeDetectorRef) {
    }

    /**
     * Initalize view model, it's important to keep names specular
     */
    ngOnInit() {
        this._vm = {
            name: this.userModel.name,
            surname: this.userModel.surname,
        };
    }

    /**
     * Helper for avoid detectchanges inside the modal, and reduce boilerplate. We could also ad an interface/type of the possibile field value, ie type fieldT= 'name' | 'surname';
     * @param field
     * @param val
     */
    protected updateModel(field, val: string): void {
        this._vm[field] = null;
        this._changeDetectionRef.detectChanges();
        this.userModel[field] = val;
        this._vm[field] = this.userModel[field];
        this._changeDetectionRef.detectChanges();
    }
}

В пользовательской модели:

....

    public get name(): string {
        return this.name';
    }

    public set name(val: string) {
        if ((new RegExp(/^[a-zA-Z]*$/).test(val))) {
            this.name = val;
        }
    }

В шаблоне:

<input type="text"  name="userName"  [ngModel]="_vm.name" (ngModelChange)="updateModel('name', $event)">
person Marco Turi    schedule 17.03.2017

Вы можете использовать (ngModelChange) и [ngModel] для проверки содержимого вашей модели при изменении.

Как вы можете видеть в этом Plunker, модель не изменится. если это недействительно.

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2><input #input type="text" [ngModel]="name" (ngModelChange)='valid(input.value)'> {{name}}</h2>
    </div>
  `,
})
export class App {
  name:string = 'ss';
  constructor() {
  }

  valid(value){
    if(value){ //<--- Your test here
      this.name = value;
    }
  }

}
person YounesM    schedule 17.03.2017