【问题标题】:How do I subscribe to changes in an angular model on an observable?如何订阅可观察对象上角度模型的更改?
【发布时间】:2018-12-05 16:25:04
【问题描述】:

我正在通过 http 加载项目列表并使用 BehaviorSubject 将更新从角度服务流式传输到组件。这些项目上有一个绑定到复选框的布尔值。

我希望另一个组件使用相同的服务并订阅相同的数据源,但只显示选中的项目。当初始数据加载时,下面的代码可以正常工作。但是如果第一个组件中的复选框被选中,它不会更新第二个组件。

我是否需要从检查的第一个组件手动更新对象并将其推回观察者?

Full example on stackblitz here

export class MyService {

    private mySubject = new BehaviorSubject<MyModel[]>([]);

    allObservable: Observable<MyModel[]>  = this.mySubject.asObservable();

    selectedObservable = this.allObservable.pipe(map(result => result.filter(f => f.selected)));

    constructor() {
        this.fundsSubject.next([
          { selected: true },
          { selected: false },
        ]);
    }
}

export class MyModel {

  public selected: boolean = false;

}

【问题讨论】:

标签: angular rxjs observable


【解决方案1】:

即使您对AppComponent 中的data 进行了更改,您的MyService 也不会意识到该更改。因此,它不会向订阅者推送新数据。

要让它知道更改,只需对以下文件进行以下更改:

AppComponent 模板:

<ul>
  <li *ngFor="let row of data">
     <input (change)="onChange()" type="checkbox" [(ngModel)]="row.selected"/> {{row.name}} 
    </li>
</ul>
<hr/>
Selected:
<hello></hello>

这个变化实际上会监听data中的变化。注意(change) 处理程序添加到input 标记。

AppComponent 类:

import { Component, OnInit } from '@angular/core';
import { MyService, MyModel } from './service.component';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  
  data: MyModel[];

  constructor(private myService : MyService){}
  
  ngOnInit() {
    this.myService.allObservable.subscribe(d => this.data = d);
  }

  onChange() {
    this.myService.setUpdatedData(this.data);
  }

}

此更改将通过调用setUpdatedData 将更改传播到服务。

并将此方法添加到MyService:

setUpdatedData(data) {
  this.mySubject.next(data);
}

此更改会将更改传播到所有subscribers。


这是一个Working StackBlitz Sample 供您参考。

【讨论】:

  • 好的,谢谢,这是有道理的。我认为必须有一种方法可以将其全部从服务中推送,但我想观察者不可能知道数据已更新。
【解决方案2】:

你的项目中有很多事情可以改进,但基本上你需要通知你的观察者发生了变化,有几种方法可以做到这一点。我刚刚添加了一个“有效”的示例,但并没有说这是一个很好的解决方案。

https://stackblitz.com/edit/angular-akfqha

// app.component.html
<input ... (change)="notifyChange()"/>

// app.component.ts
public notifyChange(): void {
    this.myService.updateData(this.data);
}

// service.component.ts (preferable named something.service.ts)
public updateData(newData: MyModel[]): void {
  this.mySubject.next(newData);
}

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    如果您在两个组件中都导入服务,则 Angular 会为每个组件提供单独的服务实例。考虑在提供者范围内添加服务。

    您可以使用注解来做到这一点:

    @Injectable({
      providedIn: 'root',
    })
    

    查找文档here

    【讨论】:

    • 谢谢,我实际上已经有了,但在我的样本中错过了它。不解决问题。我认为仅在推送新消息时才应用观察管道。我知道我是从错误的角度来做这件事的,但我对 RxJS 的了解还不够,无法了解我应该如何去做。
    【解决方案4】:

    当您订阅您的 observable 时,您只需添加一个管道过滤器并仅获取选中的项目。示例:

    import { filter } from 'rxjs/operators';
    import { BehaviorSubject } from 'rxjs';
    
    let _data: BehaviorSubject<Array<string>> = new BehaviorSubject(['']);
    
    _data.subscribe((data) => console.log(1, data)); // takes all results
    
    _data.pipe(filter((stuff: Array<string>) => stuff.some((item) => item === 'batman'))
    ).subscribe((result) => console.log(2, result)); // only takes results that pass the check
    
    _data.next(['justice']); // test 1
    _data.next(['justice', 'batman']); // test 2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 2021-11-26
      • 2017-06-07
      • 2019-08-20
      • 2020-09-16
      • 1970-01-01
      相关资源
      最近更新 更多