【问题标题】:How to finish angular observable before value changes check?如何在值更改检查之前完成角度可观察?
【发布时间】:2020-05-10 03:54:40
【问题描述】:

我正在创建一个类似于 Angular Autocomplete 的搜索栏,但我无法及时获取我的数组。

import { Component, OnInit } from '@angular/core';
import { IngredientService } from '../ingredients-shared/ingredient-service.service';
import { Ingredient } from '../ingredients-models/ingredient';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import {map, startWith} from 'rxjs/operators';
@Component({
  selector: 'app-list-ingredients',
  templateUrl: './list-ingredients.component.html',
  styleUrls: ['./list-ingredients.component.css']
})
export class ListIngredientsComponent implements OnInit {

  options: string[] = ['Angular', 'React', 'Vue'];

  mylist: Ingredient[];


  myControl = new FormControl();
  filteredOptions: Observable<Ingredient[]>;


  constructor(public ingredientService: IngredientService) { }

    ngOnInit() {

    this.ingredientService.getAllIngredients().subscribe( (ingredients: Ingredient[]) => {
      this.mylist = ingredients
    });

    this.filteredOptions = this.myControl.valueChanges.pipe(
      startWith(''),
      map(
        value => 
        this._filter(value))
    );
  }


  private _filter(value: string): Ingredient[] {

    console.log(value)
    const filterValue = value.toLowerCase();
    return this.mylist.filter(ingredient => ingredient.ingredient_name.toLowerCase().includes(filterValue));
  }

  displayIngredientName(subject: Ingredient){
    return subject ? subject.ingredient_name : undefined
  }

}

如您所见,我需要先填充 mylist,然后再检查表单中的值更改,但我不知道如何事先完成。

我尝试使用 async/await,但我不想在 ngOnInit 中使用 async。我还在订阅中插入了表单更改,但当然这只发生一次,所以它不起作用。

有什么建议吗?谢谢

编辑:这是 HTML:

    <form>
    <mat-form-field>
        <input type="text" matInput [matAutocomplete]="auto" [formControl]="myControl"/> 
        <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayIngredientName">
            <mat-option *ngFor="let ingredient of filteredList$ | async" [value]="ingredient" >
                {{ingredient.ingredient_name}}
            </mat-option>
        </mat-autocomplete>
    </mat-form-field>
</form>

【问题讨论】:

    标签: angular asynchronous observable angular-observable


    【解决方案1】:

    您需要将两个可观察对象组合成一个流,因为它们相互依赖。用户可以在加载数据之前开始输入,在加载数据之前输入的方法搜索值将被忽略。

    你可以这样实现:

    const ingredients$ = this.ingredientService.getAllIngredients();
    const searchValues$ = this.myControl.valueChanges.pipe(startWith(''), map(val => val.toLowerCase()));
    const filteredList$ = combineLatest(ingredients$, searchValues$)
                          .pipe(map(([list, searchVal]) => list.filter(item => item.ingredient_name.toLowerCase().includes(searchVal))));
    

    然后在您的模板中使用异步管道。并且不要忘记 OnPush 更改检测。使用 debounceTime 来限制快速键入的搜索操作也是一个好主意。

    【讨论】:

    • 为什么需要 OnPush 变更检测? myControl.valueChanges 不应该检测输入的变化吗?而且它似乎没有工作,我在我的模板中实现了错误吗?将 HTML 添加到问题中。
    • 您的成分服务真的返回值数组吗?您可以记录使用“点击”运算符发生的情况,然后您将看到它卡在哪里。将您的问题发布到 stackblitz,然后我会提供更详细的帮助。
    • OnPush 用于防止对每个事件、每个 setInterval、setTimeout、ajax 响应等进行更改检测...一般来说,使用它是一种好习惯。如果你生成带有原理图的组件,你会默认得到它。
    • 如果我订阅了filteredList$并填充了结果,那么它就可以工作了,是的,它会返回一个成分列表。
    • 很高兴它对您有所帮助。如果您只需要显示过滤后的数据,您就不必订阅。异步管道为您做到这一点。如果没有显式订阅它就不能工作,那么你的代码有问题。
    猜你喜欢
    • 2019-11-05
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多