Необъяснимое поведение наблюдаемого значения в форме Angular 5
Вот код компонента Angular, который можно запустить по адресу https://plnkr.co/edit/eEXt9JD3OO5rRl3p37Je?p=preview
@Component({
selector: 'my-app',
template: `
<div *ngIf="currentNumber$ | async as currentNumber">
<b>{{currentNumber}}</b>
</div>
<form [formGroup]="simpleForm">
<input type="number" formControlName="number" />
</form>
`,
})
export class App {
primeNumbers$ : Observable<number>;
simpleForm : FormGroup;
constructor() {
this.primeNumbers$ = Observable.from([3,5,7]);
this.simpleForm = new FormGroup({
number : new FormControl(1);
})
}
get currentNumber$() : Observable<number>{
return this.primeNumbers$.filter(n=>n===this.simpleForm.controls["number"].value);
}
}
Он работает по желанию: когда я набираю одно из 3,5,7 чисел во входных данных формы, оно появляется в верхней части формы, что означает, что currentNumber$ observable IS обновляется, когда элемент управления "number" меняет свое значение. Как это вообще возможно? Как Angular понимает, когда обновлять наблюдаемое в этой ситуации? Допустим, асинхронный канал подписывается на наблюдаемый. Но как компонент понимает, что новое наблюдаемое значение должно передаваться при изменении значения элемента управления формы? есть только ссылка на элемент управления формы, и он глубоко скрыт в предикате фильтра
2 ответа
Волшебная смесь заключается в том, что вы используете async
труба, которая делает оценку наблюдаемых для вас в html
шаблон, он же подписывается на наблюдаемые и реагирует на излучение наблюдаемых.
Асинхронный канал подписывается на Observable или Promise и возвращает последнее выданное им значение. Когда выдается новое значение, асинхронный канал помечает компонент, который необходимо проверить на наличие изменений. Когда компонент уничтожается, асинхронный канал автоматически отписывается, чтобы избежать возможных утечек памяти.
Редактировать:
Причина, по которой ввод текста приводит к изменению html, немного сложна. Вам нужно будет понять крючки жизненного цикла Angular. Но здесь идет:
Это работает, потому что в тот момент, когда вы вводите значение в форму ввода, оно вызывает ngOnChanges()
крючок жизненного цикла. Angular оценивает все привязки, включая эту *ngIf="currentNumber$ | async as currentNumber"
, Теперь, потому что ваш currentNumber$
собирается отфильтровать числа на основе current
значение формы (которая к тому времени уже обновлена), следовательно, она показывает только отфильтрованные числа. Вот последовательность событий.
- Инициализация компонента
this.simpleForm.controls["number"].value
содержитnull
- Вы вводите в
5
на входе. - Вы вызвали
ngOnChange
велосипедный крюк this.simpleForm.controls["number"].value
теперь содержит5
- Затем Angular переоценивает каждую привязку.
currentNumber$()
исполняется.- это фильтрует
primeNumber$
основываясь на вашемthis.simpleForm.controls["number"].value
, который сейчас содержит 5
- это фильтрует
- Angular теперь обновляет все связанные свойства
currentNumber$()
функция возвращает 5, после фильтрацииasync
труба подписывается на данные (которые уже есть)- HTML показывает
5
currentNumber$
observable вызывается каждый раз, когда что-либо в форме изменяется. Попробуйте положить console.log
в нем вроде
get currentNumber$() : Observable<number>{
console.log("observable called")
return this.primeNumbers$.filter(n=>n===this.simpleForm.controls["number"].value);
}
И вы увидите, что он вызывается не только при изменении ввода, но и при инициализации формы и т. Д.
Число, появляющееся / исчезающее, является просто результатом наблюдаемого фильтра, имеющего или не имеющего значения.