订阅数组中的所有当前和未来项目

时间:2018-01-18 01:37:23

标签: angular rxjs5 angular5

将RxJS与Angular5一起使用,我有一个包含数组的服务。 在填充数组时,将创建/销毁/重新创建一些组件。

所以我们有这样的服务:

@Injectable
export class MyService {
   public events = [];
}

然后我们有一个像这样的组件:

@Inject(MyService)
@Component({})
export class MyComponent {

  mySub: Subscriber

  constructor(private ms: MyService){}

  ngOnInit(){

   this.mySub = Rx.Observable.from(this.ms.events).subscribe(v => {

   });

  }

}

我的问题是 - 如果事件数组中包含元素,则在创建组件时,它将获取所有现有元素,但是在创建订阅后添加到数组的元素又如何呢?如何在事后将元素添加到数组中?

如果我使用Subject,问题是我认为它不会存储历史项目,只会触发新项目。

4 个答案:

答案 0 :(得分:2)

我会将事件存储在您的服务中。这样,服务可以保留所有事件的历史记录,您可以使用主题发出该历史记录。

@Injectable()
export class MyService {
    sub$ = new BehaviorSubject<any[]>([]);
    events: any[] = [];

    // add event to array and push to subject
    addEvent(event){
        this.events.push(event);
        this.sub$.next(this.events);
    }
    // find and remove event from array then push to subject
    removeEvent(event){
        let index = this.events.findIndex(item => {
            return event.id === item.id;
        });
        // if index is found, remove from array
        if(index !== -1){
            this.events.splice(index, 1);
            this.sub$.next(this.events);
        }
    }

}

我会使用行为主题,以便订阅的观察者接收最后一次发射(也可以使用重播主题)。

这是一个stackblitz演示此

答案 1 :(得分:1)

我认为@LLai拥有您需要的大部分内容,但我会将BehaviorSubject更改为ReplaySubject,并将发出更改为单个事件(鉴于Alexander Mill的回答)。

这不包括删除事件,但我没有看到提及该要求。

<强>为myService

@Injectable()
export class MyService {
  event$ = new ReplaySubject<any>();

  addEvent(event){
    this.event$.next(event);
  }
}

<强> myComponent的

ngOnInit(){
  this.mySub = this.ms.event$.subscribe(v => {
    ...
  });
}

演示

const replaySubject$ = new Rx.ReplaySubject(); 
// Also, pass in a buffer size to stop blow-out (if applicable)
// const replaySubject$ = new Rx.ReplaySubject(maxBufferSize); 


// Events before subscribe
replaySubject$.next('event1');
replaySubject$.next('event2');

replaySubject$.subscribe(console.log);

// Events after subscribe
replaySubject$.next('event3');
replaySubject$.next('event4');
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>

答案 2 :(得分:0)

好的,所以我们使用concat运算符合并两个observable,它似乎工作。从本质上讲,这个答案只是从头开始重新创建一个ReplaySubject。我建议不要使用这个答案,而是使用ReplaySubject。在任何情况下:

服务看起来像这样

@Injectable
export class MyService {

   public subject = new Rx.Subject();
   public events = [];

   addItem(v: any){
    this.events.push(v);
    this.subject.next(v);
  }
}

然后该组件看起来像这样

@Inject(MyService)
@Component({})
export class MyComponent {

  mySub: Subscriber

  constructor(private ms: MyService){}

  ngOnInit(){

    const obs = Rx.Observable.from(this.ms.events).concat(this.ms.subject);
    this.mySub = obs.subscribe(v => {

    });

  }

}

这个想法是来自数组的observable与主题连接,并且数组observable中的所有项都将首先触发。

答案 3 :(得分:0)

如果你担心状态,你应该使用一个Subject,它可以用一些数据初始化,然后传播。

@Injectable
export class MyService {
   public events = [];
   public data$: Subject<any>;

   constructor() {
     this.data$ = this.events;
   }

   addItem(v: any) {
     this.event.push(v);
     this.data$.next(this.event);
   }
}

然后在您的组件中,如果您想要实时数据源。

@Component({//usual angular stuff here})
export class MyComponent implements OnInit {
  myData: Subject<any>;

  constructor(private myService: MyService) { }

  ngOnInit() {
    this.myData = this.myService.data$;
  }
}

然后,您可以使用async管道或订阅myData来获取您的数据。