Angular: подписка не обнаруживает изменений, поэтому мое мнение не обновляется - PullRequest
0 голосов
/ 29 июня 2019

У меня есть два компонента, один из которых является дочерним маршрутом внутри html основного компонента.

Всякий раз, когда я устанавливаю флажки категорий в главном компоненте, я назначаю их переменной (строковому массиву) в службе. А в дочернем маршруте я подписываюсь на наблюдаемую переменную службы. Моя цель - обновить вид дочернего маршрута, чтобы отображались только книги этих категорий.

Так я не должен видеть журналы, как и когда значение переменной службы изменяется (потому что я дал console.log () в дочернем компоненте)? Разве подписка не получает обновленное значение при каждом изменении значения? И наконец, подписывается ли вызов метода ngOnChanges ()? (Обновить вид)

Мой код: - Parent Component.html: -

  <div class="ui-g-12">
    <p-checkbox
      name="categories"
      value="Science Fiction"
      label="Science Fiction"
      [(ngModel)]="selectedCategories"
      (onChange)="categoryFilterSelect()"
    ></p-checkbox>
  </div>
  <div class="ui-g-12">
    <p-checkbox
      name="categories"
      value="Horror"
      label="Horror"
      [(ngModel)]="selectedCategories"
      (onChange)="categoryFilterSelect()"
    ></p-checkbox>
  </div>
  <div class="ui-g-12">
    <p-checkbox
      name="categories"
      value="Suspense"
      label="Suspense"
      [(ngModel)]="selectedCategories"
      (onChange)="categoryFilterSelect()"
    ></p-checkbox>
  </div>
  <div class="ui-g-12">
    <p-checkbox
      name="categories"
      value="Romance"
      label="Romance"
      [(ngModel)]="selectedCategories"
      (onChange)="categoryFilterSelect()"
    ></p-checkbox>
  </div>
  <div class="ui-g-12">
    <p-checkbox
      name="categories"
      value="Action"
      label="Action"
      [(ngModel)]="selectedCategories"
      (onChange)="categoryFilterSelect()"
    ></p-checkbox>
  </div>
  <div style="margin-top: 10%">
    <router-outlet></router-outlet>
  </div>

Parent Component.ts: -

selectedCategories: string[] = [];
 //...

 categoryFilterSelect(){
    this.userService._filterByGenre = this.selectedCategories;
  }

ts второго компонента :-( направлено в Parent Component.html)

export class HomeComponent implements OnInit {
  allBooks: Book[] = [];
  selectedCategories: string[];
  filteredBooks: Book[];

  constructor(private userService: UserService) {}

  ngOnInit() {
    //initially display all books
    this.userService.getAllBooks().subscribe(data => {
      this.allBooks = data;
      this.filteredBooks = this.allBooks;
    });


    //This part not working
    this.userService.filterByGenre.subscribe(data => {
      this.selectedCategories = data;

      //this line not working
      console.log(this.selectedCategories);


      //perform filter logic here and update the filteredBooks array based 
      // onselected categories
    }
    );
  }
}

второй компонент.html

<div class="container">
  <div class="child" *ngFor="let book of filteredBooks">
....
  </div>
</div>

service.ts

export class UserService {

  _filterByGenre: string[] = [];
  public get filterByGenre(): Observable<string[]> {
    return of(this._filterByGenre);
  }
}

консольный вывод: - [] (Потому что изначально ни одна категория не выбрана, поэтому это регистрируется).

Мой Гит Репо: - https://github.com/Lucifer-77/ATL

Ответы [ 2 ]

1 голос
/ 29 июня 2019

@ Люцифер, все не работает так, как ты думаешь. Угловой не магический. Не беспокойтесь об этом, на первый взгляд это распространенная ошибка. Когда вы подписываетесь на Observable, Angular не ставит «старшего брата», чтобы посмотреть, что происходит с данными. например когда мы подписываемся на httpClient.get (url), который обращается к dbs, любое изменение dbs Angular не учитывает этого. (он не может этого сделать).

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

  private _filterByGenre:string[];

  private filterByGenreSource = new Subject<any>();
  filterByGenreObservable=this.filterByGenreSource.asObservable();

  get filterByGenre()
  {
    return this._filterByGenre
  }
  set filterByGenre(value)  //when we use dataService.filterBtGenre=...
  {
    this._filterByGenre=value;           //equal to the private variable
    this.filterByGenreSource.next(value) //say to Angular that something change
  }

Вы можете подписаться на filterByGenreObservable

this.dataService.filterByGenreObservable.subscribe(data => {
  this.selectedCategories = [...data]; //(*)
});

//(*) is we make simply this.selectedCategories=data, we can not see the data change
//so, I used the spread operator

Если мы сделаем что-то вроде

this.dataService.filterByGenre = this.selectedCategories;

Поскольку мы используем установщик, создайте новое значение

Хорошо, я не использую p-флажок, но вы можете быть кодом этого ответа в этом stackblitz

Обновление ну, очевидно, мы хотим сделать «что-то» при изменении категории.

Представьте, что у нас есть массив allBooks, и мы хотим фильтровать по выбранным категориям. Но сначала мы собираемся изменить данные, которые мы отправляем в службу пользователя, чтобы сделать их более похожими на p-флажок, поэтому я изменяю свою функцию categoryFileterSelect для отправки в массиве, а не [true, false, false, true] else ["Horror" "Научная фантастика"]

categoryFilterSelect() {
    this.dataService.filterByGenre =
      this.options.filter((x, index) => this.selectedCategories[index]);

  }

Итак, мы можем написать

this.userService.filterByGenreObservable.subscribe(
  data => {
    this.filteredBooks=this.allBooks.filter(x=>data.indexOf(x.genre)>=0)
  },
  error => null,
  () => console.log("error")
);

Хорошо, сначала я хочу сделать видимым вызов со значением this.userService.filterByGenre, поэтому я использую оператор rxjs startWith, и, наконец, моя подписка становится такой, как

this.userService.filterByGenreObservable.pipe(
  startWith(this.userService.filterByGenre))
  .subscribe(
  data => {
    this.filteredBooks=data?this.allBooks.filter(x=>data.indexOf(x.genre)>=0)
                           :this.allBooks
  },
  error => null,
  () => console.log("error")
);
0 голосов
/ 29 июня 2019

Пожалуйста, попробуйте следующий вызов filterByGenre () во втором компоненте.

this.userService.filterByGenre().subscribe((data:string[]) => {
  this.selectedCategories = data;

  console.log(this.selectedCategories);


  //perform filter logic here and update the filteredBooks array based 
  // onselected categories
}
...