Angular中仅在用户操作输入框时触发searchProperties.emit的问题
问题描述
我有一个搜索输入框,希望仅在用户触摸或对输入框进行输入操作时触发this.searchProperties.emit,而非在视图初始化后触发。但当前问题是视图初始化后该emit会被自动调用,寻求解决思路或帮助。
HTML代码
<mat-form-field id="property-list-filter" appearance="fill"> <mat-label style="font-size:12px">Filter properties</mat-label> <input matInput #searchInput placeholder="Ex. Property ID" #input> </mat-form-field>
TS代码片段
@ViewChild('searchInput') searchInput: ElementRef; ngAfterViewInit() { this.dataSource.sort = this.sort; this.dataSource.paginator = this.paginator fromEvent<any>(this.searchInput.nativeElement, 'keyup') .pipe( map((event) => event.target.value), startWith(''), debounceTime(500), distinctUntilChanged(), switchMap(async (search) => { this.searchProperties.emit(this.searchInput.nativeElement.value.trim().toLowerCase()) }) ) .subscribe({ complete: noop }); }
问题原因
问题出在startWith('')操作符上——这个操作符会在Observable被订阅时(也就是组件ngAfterViewInit执行阶段)立即发出一个空值,直接触发后续switchMap里的emit调用,导致初始化阶段就执行了搜索逻辑。
解决方案
方案1:移除startWith('')(最直接)
直接删掉startWith(''),这样Observable只会在用户触发keyup事件时才会发出值,初始化阶段不会触发emit。同时可以优化代码,直接使用map传递过来的search参数,避免重复获取DOM值:
@ViewChild('searchInput') searchInput: ElementRef; ngAfterViewInit() { this.dataSource.sort = this.sort; this.dataSource.paginator = this.paginator fromEvent<any>(this.searchInput.nativeElement, 'keyup') .pipe( map((event) => event.target.value), debounceTime(500), distinctUntilChanged(), switchMap(async (search) => { this.searchProperties.emit(search.trim().toLowerCase()) }) ) .subscribe({ complete: noop }); }
方案2:保留startWith但过滤初始值
如果需要保留startWith的其他逻辑(比如初始状态的处理),可以在switchMap前添加filter操作符,过滤掉初始发出的空值:
fromEvent<any>(this.searchInput.nativeElement, 'keyup') .pipe( map((event) => event.target.value), startWith(''), debounceTime(500), distinctUntilChanged(), // 过滤掉索引为0的初始值,只处理用户操作产生的事件 filter((_, index) => index !== 0), switchMap(async (search) => { this.searchProperties.emit(search.trim().toLowerCase()) }) ) .subscribe({ complete: noop });
方案3:改用input事件覆盖更多输入场景
keyup事件可能漏掉粘贴、输入法联想等输入场景,改用input事件能覆盖所有用户输入操作,同时配合移除startWith,体验更完善:
fromEvent<any>(this.searchInput.nativeElement, 'input') .pipe( map((event) => event.target.value), debounceTime(500), distinctUntilChanged(), switchMap(async (search) => { this.searchProperties.emit(search.trim().toLowerCase()) }) ) .subscribe({ complete: noop });
内容的提问来源于stack exchange,提问作者Tim Launders
相关产品推荐
相关产品推荐

