Начнем с более подробного изучения директивы ngModel
API , вы увидите, что ngModel
- это @Input
привязка , которая принимает некоторое значение в качестве переменной model
.Во время инициализации ngModel
control он создает FormControl
неявно.
public readonly control: FormControl = new FormControl();
Магия обновления model
значения происходит от ngOnChanges
hook , таким образом он синхронизирует значение представления со значением model
.Если вы присмотритесь к ловушке ngOnChanges
, вы обнаружите, что она проверяет ввод и применяет другие проверки, а затем строго проверяет, действительно ли значение ngModel
действительно изменено с использованием метода isPropertyUpdated
.
ngOnChanges - ngModel
директива
ngOnChanges(changes: SimpleChanges) {
this._checkForErrors();
if (!this._registered) this._setUpControl();
if ('isDisabled' in changes) {
this._updateDisabled(changes);
}
if (isPropertyUpdated(changes, this.viewModel)) {
this._updateValue(this.model); // helps to update
this.viewModel = this.model;
}
}
private _updateValue(value: any): void {
resolvedPromise.then(() => {
// set value will set form control
this.control.setValue(value, {emitViewToModelChange: false});
});
}
Но чтобы это произошло, Angular должен распознавать изменения во время цикла обнаружения изменений.И поскольку мы не изменили нашу модель, она не вызовет хук ngOnChanges:
То, что я до сих пор объяснял, было частью API.Вернемся к вопросу.
Попробуйте ниже фрагмент в stackblitz , каковы будут наши ожидания.При изменении входного значения оно должно само установить это значение 10
.
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate = 10"
name="rate" />
К сожалению, этого не произойдет, вы увидите, что при первоначальном наборе любого числа это изменит входное значениедо 10
и позже все, что вы введете, будет добавляться к вводу номера.Ааа, интересно почему?
Вернемся снова к исходному вопросу,
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate=roundRate($event)"
name="rate" />
{{model.rate}}
ngModel
используется как односторонняя привязка.Ожидаемое поведение: все значения, присвоенные model.rate
, должны быть отражены внутри input
.Давайте попробуем ввести 1.1, вы увидите, что она показывает нам значение 1.1
.Теперь попробуйте ввести 1.2
, в результате 1,2 приведет к 1
.Интересно, почему?Но, конечно, model.rate
привязки обновляются правильно.Точно так же проверьте для 4.6
, 4.8
результат в 5, который отлично работает.
Давайте разберем это в примере выше, что происходит, когда вы пытаетесь ввести 1.1
.
- type
1
=> model.rate становится 1
- type
1.
=> model.rate остается 1
- type
1.1
=> model.rate остается 1
В конце концов, когда вы набираете 1.1
или 1.2
значение модели остается 1
, так как мы Math.round
значение.Так как значение model.rate
не обновляется, все, что вы вводите дальше, просто игнорируется привязкой ngModel
и отображается внутри поля input
.
Проверка на 4.6
, 4.8
работает отлично.Зачем?пошагово разбить его
- type
4
=> model.rate становится 4
- type
4.
=> model.rate остается 4
- type
4.6
=> model.rate становится 5
Здесь, когда вы вводите 4.6
в текстовое поле, Math.round
значение становится 5
.что означает изменение значения model.rate
(ngModel), приведет к обновлению значения поля input
Теперь начните читать ответ еще раз, объясненный изначально технический аспект также будет очищен.
Примечание: читая ответ, следуйте ссылкам, предоставленным во фрагменте, это может помочь вам более точно понять его.
Чтобы это работало, попробуйте обновить поля на blur
/ change
, где это событие запускается в фокусе из fields
, как Sid's answer
.Это сработало, потому что вы обновляете модель один раз, когда поле выделено.
Но работает только один раз.Чтобы постоянно обновлять информацию, мы можем сделать несколько трюков:
this.model.rate = new String(Math.round(value));
, которые будут давать новую ссылку на объект каждый раз, когда мы округляем наше значение.
Фрагмент в Stackblitz