简体   繁体   English

如何订阅可观察对象的角度模型的更改?

[英]How do I subscribe to changes in an angular model on an observable?

I'm loading a list of items over http and using a BehaviorSubject to stream the updates from an angular service to a component.我正在通过 http 加载项目列表,并使用 BehaviorSubject 将更新从角度服务流式传输到组件。 The items have a boolean on them which is bound to a checkbox.这些项目上有一个绑定到复选框的布尔值。

I want another component to use the same service and subscribe to the same data source, but only show the items that are checked.我希望另一个组件使用相同的服务并订阅相同的数据源,但只显示选中的项目。 This code below works fine when the initial data loads.当初始数据加载时,下面的代码工作正常。 But if the checkbox in the first component is checked, it doesn't update the second component.但是如果第一个组件中的复选框被选中,它不会更新第二个组件。

Do I need to manually update the object from the first component on check and push it back into the observer?我是否需要在检查时从第一个组件手动更新对象并将其推回观察者?

Full example on stackblitz here 关于stackblitz的完整示例在这里

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;

}

Even if you're making changes to the data in the AppComponent , your MyService is not aware of the change.即使您对AppComponentdata进行了AppComponent ,您的MyService也不会知道该更改。 Hence it is not pushing new data to the subscribers.因此,它不会向订阅者推送新数据。

To make it aware of the change, just make the following changes to the following files:要使其了解更改,只需对以下文件进行以下更改:

AppComponent Template:应用组件模板:

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

This change will actually listen to the change in data .这种变化实际上会监听data的变化。 Notice the (change) handler added to the input tag.请注意添加到input标记的(change)处理程序。

AppComponent Class:应用组件类:

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);
  }

}

This change will propagate the change to the service by calling the setUpdatedData on it.此更改将通过调用setUpdatedData将更改传播到服务。

And add this method to the MyService :并将此方法添加到MyService

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

This change will propagate the change to all the subscribe rs.此更改会将更改传播到所有subscribe rs。


Here's a Working StackBlitz Sample For your ref.这是一个工作 StackBlitz 示例供您参考。

There is all lot of things going on in your project that can be improved, but basically you need to notify your observer that a change has taken place, there are several way to do this.你的项目中有很多事情都可以改进,但基本上你需要通知你的观察者发生了变化,有几种方法可以做到这一点。 I have just added one example "that works", without saying it is a good solution.我刚刚添加了一个“有效”的例子,但没有说这是一个很好的解决方案。

https://stackblitz.com/edit/angular-akfqha 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);
}

Hope this helps!希望这可以帮助!

If you are importing the service in both the components, angular gives separate instances of the service for each of the components.如果您在两个组件中都导入服务,angular 会为每个组件提供单独的服务实例。 Consider adding the service in the provider scope.考虑在提供者范围内添加服务。

You can use the annotation to do that:您可以使用注释来做到这一点:

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

Look for documentation here 在此处查找文档

When you subscribe to your observable you can just add a pipe filter and take only the checked items.当您订阅 observable 时,您只需添加一个管道过滤器并仅获取选中的项目。 Example:例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM