【问题标题】:Observable subscription on onInit only runs onceonInit 上的 Observable 订阅只运行一次
【发布时间】:2020-08-16 15:01:54
【问题描述】:

我有一个带有名称的表格和一个输入标签,当值更改时,它会过滤表格的内容。 数据来自服务上的 http 请求。

我有三种情况:

1- 如果我仅在 ngOninit() 上订阅 this.ds.getDrogas(),表格会显示所有内容,但过滤器不起作用。 2-如果我仅在filterName() 上订阅this.ds.getDrogas(),则表开始为空,但是当我更改输入 y 的值时开始正常工作。如果我删除输入的内容,表格会显示所有数据,如果我再次写一些东西,过滤器就会工作。 3-如果我同时订阅它,它会按预期工作。表格开始显示所有内容,当输入值更改时,过滤器起作用。

我知道ngOnInit() 中的代码只运行一次,但订阅不应该一直监听可观察到的变化?

提前感谢您的帮助。

服务端:

getDrogas(): Observable <HttpResponses> {
    return this.http.get<HttpResponses>(this.apiUrl +'/drogas')
  }

表格组件.ts:

    ngOnInit{
        this.ds.getDrogas().pipe(
        map((data)=> data.data
        .filter(element=> element.identificacion.nombre.startsWith(this.contador))))
        .subscribe(res=> {this.dataDroga= res; console.log('Ejecutado con valor de contador'+ 
        this.contador)});
    }

   contador: string =''

   filterName(){
   this.ds.getDrogas()
   console.log(this.dataDroga)
   }

表格组件.html:

<input  type="text" [(ngModel)]='contador' (ngModelChange)='filterName()'>

【问题讨论】:

    标签: angular typescript angular2-observables ngoninit


    【解决方案1】:

    this.ds.getDrogas() - 返回一个 Observable。 Angular 不会在没有订阅的情况下从服务器请求数据。您在 ngOnInit() 中订阅它 - 这就是您获得初始数据的原因。

    我建议在 ngModelChange 处理程序中使用带有主题的 denounceTime 运算符,以防止每次更改都调用 API。它看起来像这样:

    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
    
      filterValue$ = new BehaviorSubject('');
      filterValue = '';
    
      constructor(private api: ApiSerive) {}
    
      ngOnInit(): void {
        this.filterValue$.pipe(
          debounceTime(DEBOUNCE_TIME),
          switchMap(filterValue => this.api.getData().pipe(
            map(dataFromServer => filterData(dataFromServer, filterValue)),
          )),
          /* UNSUBSCRIBE HERE on compoennt destroy */
          tap(filteredData => {
            console.log(filteredData);
            /* LOGIC OF UPDATE TABLE */
          }),
        ).subscribe();
      }
    
      onFilterChanged(value: string): void {
        console.log(value);
        this.filterValue$.next(value);
      }
    }
    
    function filterData(dataFromServer: any, filterValue): any {
      // SOME LOGIC HERE
      return dataFromServer;
    }
    

    完整代码在这里https://stackblitz.com/edit/angular-txwgmk

    附言

    不要忘记取消订阅组件中的 observables。

    希望对你有帮助!

    【讨论】:

    • 我明白,但我不喜欢两个相等的订阅。如果我在服务上创建一个主题并使其发出一个值,我可以订阅我的组件中的主题。因此,每次调用 this.ds.getDrogas 都会通过主题发出值。这会是一个好的解决方案吗?
    • 您必须订阅发出 HTTP 请求的 Observable。我已经更新了一个答案以显示它的外观
    • 这是一个正确的答案,但是,我们应该分解出共享逻辑,而不是复制粘贴,这很简单。 filterName() { this.loadData() }ngOnInit() {this.loadData()}
    • 它没有复制粘贴。我已经编辑了我的答案以更新
    • 如果对您有用,请将其标记为答案。谢谢。
    猜你喜欢
    • 2018-05-22
    • 2023-03-15
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多