angular - Angular:订阅未检测到更改,因此我的视图未更新
问题描述
我有两个组件,其中一个是主组件 html 内的子路由。
每当我在主组件中选择类别复选框时,我都会将它们分配给服务中的变量(字符串数组)。在子路由中,我订阅了这个服务变量的一个 observable。我的目标是更新子路线的视图以仅显示这些类别的书籍。
那么我不应该在服务变量的值发生变化时看到日志吗(因为我在子组件中给出了 console.log() )?每次值更改时,订阅不会获得更新的值吗?最后,订阅是否调用了 ngOnChanges() 方法?(更新视图)
我的代码:- 父 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>
父组件.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>
服务.ts
export class UserService {
_filterByGenre: string[] = [];
public get filterByGenre(): Observable<string[]> {
return of(this._filterByGenre);
}
}
控制台输出:- [] (因为最初没有选择任何类别,所以会记录下来)。
我的 Git 仓库:- https://github.com/Lucifer-77/ATL
解决方案
@Lucifer,事情不像你想象的那样工作。Angular 并不神奇。别担心,起初这是一个常见的错误。当你订阅一个 Observable 时,Angular 不会放一个“老大哥”来看看数据会发生什么。例如,当我们订阅调用 dbs 的 httpClient.get(url) 时,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;
当我们使用 setter 时,发出一个新值
好吧,我不使用 p-checkbox,但你可以在这个stackblitz中成为这个答案的代码
更新好,显然我们想在更改类别时做出“一些事情”。
想象一下,我们有一个名为 allBooks 的数组,我们希望按所选类别进行过滤。但首先我们要更改发送给用户服务的数据,使其更类似于 p-checkbox,因此我将函数 categoryFileterSelect 更改为以数组形式发送 not [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")
);
推荐阅读
- servicestack - 允许不安全域上的 cookie
- javascript - 在 JavaScript 中创建 GIF 和 PNG
- python - 如何在不使用熊猫的情况下从 s3 存储桶获取 excel 文件并将文件再次上传到 s3 存储桶 - Python
- flutter - Flame 0.29.4 无法以可靠的零安全运行
- php - PHP - 如何确定文件在 public_html 文件夹中?
- python - 如何根据if语句设置Python(全局?)变量值
- sql - 如何申请加入sequelize
- sql - SQL - 每小时选择最多数量的类别
- css - 从 antd 设计中删除页脚后的样式问题
- openlayers - Openlayers 6.9.0:更改鼠标位置坐标的位置