Правильный способ заполнить параметры выбора angular7 удаленными данными?

Я пытаюсь загрузить параметры выбора асинхронно из удаленного источника (API календаря Google).

Я могу загружать параметры удаленно из источника, отличного от Google: stackblitz

Но когда я пытаюсь загрузить из Google API, он не отображает параметры, ПОКА я не нажимаю раскрывающийся список выбора ИЛИ Я устанавливаю значение (FormControl.setValue()) одним нажатием кнопки.

Почему? Единственный способ заставить его работать - это вызвать в ChangeDetectorRef.detectChanges(); после звонка в FormControl.setValue().

Здесь - это стек, который показывает проблему.

Несколько замечаний по поводу неработающего stackblitz:

  1. Это требует, чтобы вы вошли в систему через Google и предоставили моему идентификатору клиента доступ для чтения к вашим календарям. Вы можете заглянуть в мой источник и увидеть, что я делаю все гнусные. Вы также можете отозвать доступ с вашего страница разрешений google, мое имя приложения - ShiftCals.
  2. Откройте Console в stackblitz. Он сообщит вам, когда выбранные параметры (календари) были загружены из Google API.
  3. Чтобы воспроизвести, нажмите кнопку входа в систему с помощью Google, затем подождите, пока не появится поле выбора. Он будет пустым. Щелчок по выбору или нажатие set 1st option приведет к повторному рендерингу выбора.
  4. Чтобы повторно запустить тестовую итерацию, вам необходимо перезагрузить фрейм предварительного просмотра stackblitz.

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

Вы используете push?

Vova Bilyachat 06.12.2018 00:55

хм, не понимаю, что вы имеете в виду - вы можете спросить по-другому?

rynop 06.12.2018 03:11

Не могли бы вы предоставить полный исходный код вашего компонента?

Vova Bilyachat 06.12.2018 03:11

Есть ли причина, по которой у вас есть matNativeControl вместо того, чтобы делать элемент mat-select в соответствии с документацией? Кроме того, можете ли вы подтвердить, какую версию Angular-Material вы используете?

nclarx 06.12.2018 03:29

IMO легче выбирать на мобильных устройствах при использовании собственного выбора. @ angular / материал 7.0.3. Я обновил свой q. Благодарность

rynop 06.12.2018 03:34

Простым решением было бы просто вызвать angular.io/api/core/ChangeDetectorRef detectChanges.

Vova Bilyachat 06.12.2018 03:51

Я не уверен, но думаю, что проблема связана с async и ngZone

Vova Bilyachat 06.12.2018 03:52
this.ref.detectChanges(); сделал свое дело, но это похоже на взлом. Я согласен, что это, вероятно, проблема с синхронизацией, связанная с async, однако загрузка удаленных данных для использования в select должна быть очень распространенным шаблоном. Мне сложно найти наглядный пример использования этого шаблона. Вы думаете, если я сделаю calendarList и Observable и сделаю let cal of calendarList | async, это сработает? Думаю, нет.
rynop 06.12.2018 04:06

Готовлю ответ, но есть несколько вопросов - зачем вам сравнивать? Это множественный выбор? Я определенно думаю, что вам нужен async на вашем *ngFor

nclarx 06.12.2018 04:13

спасибо заранее @nclarx. Добавление `| async` выдает ошибку, поскольку calendarList - это просто простой список JS. В документации предлагается использовать compareWith при загрузке удаленных данных. Пример: я перезагружаюсь с удаленного компьютера, возвращаемые данные не меняются, но angular этого не знает. @ см. angular.io/api/forms/…. Завтра я поработаю над примером stackblitz, если не смогу в ближайшее время в этом разобраться.

rynop 06.12.2018 04:18

Если вы сделаете Stackblitz, я буду счастлив поиграть с ним - у меня есть аналогичная вещь, которую я решил в одном из своих проектов. Может быть, быстрее, чем я, предоставлю здесь что-нибудь, что не по плану. Напишите ссылку в qtn, и я посмотрю на Stackblitz

nclarx 06.12.2018 04:20

Я реорганизовал использование Observable, и он по-прежнему работает, только если this.ref.detectChanges(); вызывается ПОСЛЕ this.calendarListControl.setValue(). ТАК расстраивает. Завтра буду работать над stackblitz.

rynop 06.12.2018 05:03

@nclarx Я добавил 2 stackblitzes. 1-й работает, как я ожидал, при загрузке из удаленного источника, 2-й при загрузке через Google API (не работает). Заранее спасибо за помощь.

rynop 06.12.2018 17:34
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
13
859
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я понял.

Ответ заключается в том, как Angular обнаруживает изменения. Сообщение в блоге Зоны в угловом объясняет это лучше всего, но, вкратце, Angular полагается на изменения состояния (события, удаленные выборки и т. д.), Чтобы инициировать обнаружение изменений. Эти изменения состояния отслеживаются, только если они происходят в угловой зоне.

Мой stackblitz с проблемой выходит из зоны, потому что, я думаю, часть Google JS (gapi.load()) работает в iFrame. В любом случае именно здесь выполнение выходит из зоны Angular.

Вот обновленный stackblitz с реализацией, которая работает.

Что я здесь сделал, так это обернул gapi.load() в Promise, контекст которого находится в зоне. Кроме того, разрешение Promises - это событие, которое запускает логику обнаружения изменений Angular.

Новичку в Angular вроде меня было непросто отследить это, но я многому научился. Если эта тема вас интересует, это сообщение в блоге сделает еще один шаг и поговорит о том, как улучшить качество рисования.

Другие вопросы по теме