根据输入值更新 ngif
update ngif depending on input value
我正在尝试搜索以过滤博客中的帖子
这些帖子是从 ngrx 商店作为可观察的
因此,当用户更改输入的值时,帖子 (with async pipe) 将由名为 filter-posts[=26 的管道更新=]
如果新数组为空,则应显示一条消息 'no posts found'
问题是更改输入值后未显示消息
这是代码:
posts.component.html:
<div class="posts">
<!--search-->
<input
[(ngModel)]="searchValue"
class="p-2 rounded border w-100 bg-secondary text-light" type="search"
placeholder="Search..." id="search">
<!--posts-->
<ng-container *ngIf="(posts | async).length > 0; else noPosts">
<div class="post" *ngFor="let post of posts | async | filterPosts:searchValue">
<div class="p-title">
<a (click)="goTo('blog/posts/' + post.id.toString(), post)">{{post.title}}</a>
</div>
<div class="p-image">
<img [src]="post.imageSrc" [alt]="post.title">
</div>
<div class="p-cont">
{{post.content | slice:0:80}}
</div>
<div class="p-category">
<a *ngFor="let category of post.categories" class="p-1 m-1 text-light fw-bold">{{category}}</a>
</div>
<div class="p-date">
{{post.date}}
</div>
<app-author class="p-author d-block" [author]="post.author"></app-author>
</div>
</ng-container>
<ng-template #noPosts>
<div class="bg-danger w-100">No Posts Found</div>
</ng-template>
</div>
posts.component.ts:
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Router } from '@angular/router';
import { faSearch } from '@fortawesome/free-solid-svg-icons';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Post } from 'src/app/models/post';
import { User } from 'src/app/models/user';
import { setSelectedPostId } from 'src/app/state/posts/actions';
import { getPosts, PostState } from 'src/app/state/posts/reducer';
import { getUserById } from 'src/app/state/users/reducer';
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.scss']
})
export class PostsComponent {
constructor(private store: Store<PostState>, private router: Router) { }
search = faSearch;
searchValue: string = '';
goTo(path: string, post: Post) {
this.router.navigate([path]);
this.setSelectedPost(post.id);
}
setSelectedPost(id: string) {
this.store.dispatch(setSelectedPostId({id}));
}
getUser(id: string): Observable<User> {
return this.store.select(getUserById(id));
}
posts: Observable<Post[]> = this.store.select(getPosts);
}
过滤器-posts.pipe.ts:
import { Pipe, PipeTransform } from '@angular/core';
import { Post } from '../models/post';
@Pipe({
name: 'filterPosts',
pure: false
})
export class FilterPostsPipe implements PipeTransform {
transform(value: Post[], searchValue: string): Post[] {
return value.filter(
(post) =>
post.title.toLowerCase().includes(searchValue.toLowerCase()) ||
post.content.toLowerCase().includes(searchValue.toLowerCase()) ||
post.author.name.toLowerCase().includes(searchValue.toLowerCase()) ||
post.categories.includes(searchValue.toLowerCase())
);
}
}
对这种操作使用 pipe
一开始似乎是个好主意,但是当你依赖一个在每个变化检测周期都会 运行 的不纯管道时,性能应用程序的安全性可能会受到损害。
有更简单的方法可以根据另一个值过滤可观察值,我的建议是将搜索输入的值也视为流。
如果我们不使用 [(ngModel)]
而使用 FormControl
来监听输入的 valueChanges
observable,我们可以组合流并过滤 posts
值基于 search
值。
你会得到这样的结果
// Create a form control for the search input
searchControl = new FormControl();
..........................
posts: Observable<Post[]> = combineLatest([
this.store.select(getPosts),
this.searchControl.valueChanges.pipe( // Listen for the changes of the form control
debounceTime(250), // dont search for every keystroke
startWith(''), // start with an empty string to show all posts
)
]).pipe(
map(([ posts, searchValue ]) => posts.filter(post => {
return post.title.toLowerCase().includes(searchValue.toLowerCase()) ||
post.content.toLowerCase().includes(searchValue.toLowerCase()) ||
post.author.name.toLowerCase().includes(searchValue.toLowerCase()) ||
post.categories.includes(searchValue.toLowerCase())
})
)
);
然后在您的模板中连接表单控件
<input [formControl]="searchControl"
...>
有了这个,就不需要管道了,当可观察值改变时,视图应该更新。
我正在尝试搜索以过滤博客中的帖子
这些帖子是从 ngrx 商店作为可观察的
因此,当用户更改输入的值时,帖子 (with async pipe) 将由名为 filter-posts[=26 的管道更新=]
如果新数组为空,则应显示一条消息 'no posts found'
问题是更改输入值后未显示消息
这是代码:
posts.component.html:
<div class="posts">
<!--search-->
<input
[(ngModel)]="searchValue"
class="p-2 rounded border w-100 bg-secondary text-light" type="search"
placeholder="Search..." id="search">
<!--posts-->
<ng-container *ngIf="(posts | async).length > 0; else noPosts">
<div class="post" *ngFor="let post of posts | async | filterPosts:searchValue">
<div class="p-title">
<a (click)="goTo('blog/posts/' + post.id.toString(), post)">{{post.title}}</a>
</div>
<div class="p-image">
<img [src]="post.imageSrc" [alt]="post.title">
</div>
<div class="p-cont">
{{post.content | slice:0:80}}
</div>
<div class="p-category">
<a *ngFor="let category of post.categories" class="p-1 m-1 text-light fw-bold">{{category}}</a>
</div>
<div class="p-date">
{{post.date}}
</div>
<app-author class="p-author d-block" [author]="post.author"></app-author>
</div>
</ng-container>
<ng-template #noPosts>
<div class="bg-danger w-100">No Posts Found</div>
</ng-template>
</div>
posts.component.ts:
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Router } from '@angular/router';
import { faSearch } from '@fortawesome/free-solid-svg-icons';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Post } from 'src/app/models/post';
import { User } from 'src/app/models/user';
import { setSelectedPostId } from 'src/app/state/posts/actions';
import { getPosts, PostState } from 'src/app/state/posts/reducer';
import { getUserById } from 'src/app/state/users/reducer';
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.scss']
})
export class PostsComponent {
constructor(private store: Store<PostState>, private router: Router) { }
search = faSearch;
searchValue: string = '';
goTo(path: string, post: Post) {
this.router.navigate([path]);
this.setSelectedPost(post.id);
}
setSelectedPost(id: string) {
this.store.dispatch(setSelectedPostId({id}));
}
getUser(id: string): Observable<User> {
return this.store.select(getUserById(id));
}
posts: Observable<Post[]> = this.store.select(getPosts);
}
过滤器-posts.pipe.ts:
import { Pipe, PipeTransform } from '@angular/core';
import { Post } from '../models/post';
@Pipe({
name: 'filterPosts',
pure: false
})
export class FilterPostsPipe implements PipeTransform {
transform(value: Post[], searchValue: string): Post[] {
return value.filter(
(post) =>
post.title.toLowerCase().includes(searchValue.toLowerCase()) ||
post.content.toLowerCase().includes(searchValue.toLowerCase()) ||
post.author.name.toLowerCase().includes(searchValue.toLowerCase()) ||
post.categories.includes(searchValue.toLowerCase())
);
}
}
对这种操作使用 pipe
一开始似乎是个好主意,但是当你依赖一个在每个变化检测周期都会 运行 的不纯管道时,性能应用程序的安全性可能会受到损害。
有更简单的方法可以根据另一个值过滤可观察值,我的建议是将搜索输入的值也视为流。
如果我们不使用 [(ngModel)]
而使用 FormControl
来监听输入的 valueChanges
observable,我们可以组合流并过滤 posts
值基于 search
值。
你会得到这样的结果
// Create a form control for the search input
searchControl = new FormControl();
..........................
posts: Observable<Post[]> = combineLatest([
this.store.select(getPosts),
this.searchControl.valueChanges.pipe( // Listen for the changes of the form control
debounceTime(250), // dont search for every keystroke
startWith(''), // start with an empty string to show all posts
)
]).pipe(
map(([ posts, searchValue ]) => posts.filter(post => {
return post.title.toLowerCase().includes(searchValue.toLowerCase()) ||
post.content.toLowerCase().includes(searchValue.toLowerCase()) ||
post.author.name.toLowerCase().includes(searchValue.toLowerCase()) ||
post.categories.includes(searchValue.toLowerCase())
})
)
);
然后在您的模板中连接表单控件
<input [formControl]="searchControl"
...>
有了这个,就不需要管道了,当可观察值改变时,视图应该更新。