Необъяснимое поведение наблюдаемого значения в форме 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 обновляется, когда элемент управления "number" изменяет свое значение. Как это вообще возможно? Как angular понимает, когда в этой ситуации обновлять наблюдаемое? Допустим, асинхронный канал подписывается на наблюдаемый. Но как компонент понимает, что новое наблюдаемое значение должно выдаваться при изменении значения элемента управления формы? есть только ссылка на элемент управления формы, и он глубоко спрятан в предикате фильтра


person sovo2014    schedule 06.02.2018    source источник


Ответы (2)


Волшебная смесь получается потому, что вы используете async pipe, который выполняет оценку наблюдаемых за вас в шаблоне html он подписывается на наблюдаемые и реагирует на выброс наблюдаемых.

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

Редактировать:

Причина, по которой ввод данных приводит к изменению HTML, немного сложна. Вам нужно будет понять крючки жизненного цикла Angular. Но вот идет:

Это работает, потому что в тот момент, когда вы вводите значение в форму ввода, запускается ловушка жизненного цикла ngOnChanges(). Angular оценит все привязки, включая эту *ngIf="currentNumber$ | async as currentNumber". Теперь, поскольку ваш currentNumber$ будет отфильтровывать числа на основе значения current формы (которое к тому времени уже обновлено), следовательно, он показывает только отфильтрованные числа. Вот последовательность событий.

  1. Component initialize
    • this.simpleForm.controls["number"].value contains null
  2. Вы вводите 5 в поле ввода.
  3. Вы активировали хук ngOnChange цикла.
  4. this.simpleForm.controls["number"].value теперь содержит 5
  5. Затем Angular повторно оценивает каждую привязку.
  6. currentNumber$() gets executed.
    • it filters the primeNumber$ based on your this.simpleForm.controls["number"].value, which now contains 5
  7. Angular теперь обновляет все связанные свойства
  8. currentNumber$() функция возвращает 5 после фильтрации
  9. async pipe подписывается на данные (которые уже есть)
  10. HTML показывает 5
person CozyAzure    schedule 06.02.2018
comment
Спасибо за примечание! :-) - person sovo2014; 06.02.2018
comment
Но хорошо, допустим, что async подписывается на наблюдаемое. Но как компонент понимает, что новое наблюдаемое значение должно выдаваться при изменении значения элемента управления формы? есть только ссылка на элемент управления формы, и он глубоко спрятан в предикате фильтра - person sovo2014; 06.02.2018
comment
@ sovo2014 из-за этого this.simpleForm.controls["number"].value. Свойство .value объекта FormControl всегда будет возвращать текущее значение ввода и, следовательно, поведение. - person CozyAzure; 06.02.2018
comment
Я знаю, что там есть ссылка на значение элемента управления формы. Я не понимаю, КАК компоненты понимают, что это есть. Единственный способ, которым я могу это видеть, - это синтаксический анализ исходного кода, построение дерева AST и т. Д. - person sovo2014; 06.02.2018
comment
Понятно. Так что это не волшебство. Это просто Angular настолько глуп, что переоценивает каждую привязку, даже если она может остаться нетронутой. - person sovo2014; 06.02.2018

Наблюдаемый currentNumber$ вызывается каждый раз, когда что-либо в форме изменяется. Попробуйте вставить в него console.log, например

get currentNumber$() : Observable<number>{
  console.log("observable called")
  return this.primeNumbers$.filter(n=>n===this.simpleForm.controls["number"].value);
}

И вы увидите, что он вызывается не только при изменении ввода, но также при инициализации формы и т. Д.

Число появляющихся / исчезающих - это просто результат того, что наблюдаемый фильтр имеет или не имеет значения.

person SWeko    schedule 06.02.2018