Установка выбранного элемента элемента select с помощью асин c труб в Angular - PullRequest
0 голосов
/ 27 апреля 2020

Angular экспертов! Я пытаюсь понять asyn c трубы в Angular, но я застрял в базовом сценарии c. У меня есть два элемента выбора в пользовательском интерфейсе, один из которых содержит сообщения, а другой содержит связанные комментарии. Я хочу установить публикацию (последнюю) как изначально выбранную для элемента выбора, отображающего сообщения, и хочу использовать выбранный элемент для фильтрации связанных комментариев во втором выборе. Это не работает в моем коде, для которого я создал упрощенную версию в Stackblitz:

https://stackblitz.com/edit/angular-p6ynuy

Может кто-нибудь из вас объяснить мне, что я ' я делаю неправильно? Это соответствующий фрагмент кода и HTML:

ngOnInit() {
    this.postList$ = this.getPostList();

    // latestPost$ is not is use yet, but maybe it could be used to set the selected post?
    this.latestPost$ = this.postList$ 
      .pipe(
        map(posts => posts[posts.length - 1])
      );

    this.selectedPost$ = combineLatest([
      this.postList$,
      this.postSelectedAction$
    ])
      .pipe(
        map(([posts, selectedPostId]) => posts.find(post => post.id === selectedPostId))
      );

    this.commentList$ = this.selectedPost$
      .pipe(switchMap(
        post => this.getCommentList(post)
      ));
  }


<select [ngModel]="selectedPost$ | async" (change)="onSelected($event.target.value)">
  <option *ngFor="let post of postList$ | async" [ngValue]="post">
    {{post.id}} {{post.title}}
  </option>
</select>
<select>
  <option *ngFor="let comment of commentList$ | async" [ngValue]="comment">
    {{comment.id}} {{comment.postId}} {{comment.name}}
  </option>
</select>

1 Ответ

1 голос
/ 27 апреля 2020

Angular Сравнивает объекты по ссылке по умолчанию

Вы почти там. Проблема в том, что ваш select получает список option с ссылкой на Post s как часть ngFor. Теперь, чтобы узнать, какой option выбран в данный момент, Angular сравнивает каждый объект post с текущим значением selectedPost$ | async.

По умолчанию используется оператор ===. Оператор === сравнивает примитивы по значению, но объекты по ссылке. Пример:

console.log('a' === 'a');
const obj = {'a': 'b'};
const obj2 = obj;
console.log(obj === obj2);
console.log(obj === {'a': 'b'});

Таким образом, чтобы post считался тем же постом, что и selectedPost$ | async, они должны быть фактически тем же объектом, а не просто объектом, который выглядит то же самое.

Вы фактически получаете несколько копий одного и того же сообщения, а не только одно сообщение

Теперь это не так: поскольку вы используете async В случае обнаружения изменений сообщения перезагружаются из API. Когда вы просматриваете вкладку сети вашего браузера, вы можете увидеть, что есть три запроса:

enter image description here

Полезная нагрузка ответа на все запросы одинакова, но поскольку объекты Post возвращаются три раза, они сохраняются в памяти три раза. JavaScript не может знать, что они на самом деле одинаковы, и сравнение === возвращает false.

Решение: предоставьте свою compareWith функцию

Как вы можете решить это? Вы можете Angular правильно сравнить Post объектов в вашем select. Вам просто нужно задать себе вопрос: откуда мне знать, что два Post объекта на самом деле являются одним и тем же объектом? В данном случае ответ таков: когда они имеют одинаковый идентификатор.

Теперь вы можете написать свою собственную инструкцию для Angular для сравнения объектов или выбора: просто добавьте ввод compareWith в выбор :

<select [ngModel]="selectedPost$ | async" 
(change)="onSelected($event.target.value)"
[compareWith]="comparePosts"
>

Теперь Angular знает, как использовать метод с именем comparePosts для сравнения двух сообщений. Теперь, как этот метод может выглядеть? Например, вот так:

comparePosts(p1: Post, p2: Post) {
    return p1.id === p2.id;
}

Теперь Angular знает, как правильно сравнить два Post объекта, и ваша проблема решена.

PS: Пожалуйста, не забудьте написать лучше comparePosts метод, чем я, например, также правильно обрабатывает undefined и null значения.

...