0

Trying to construct a schedule using RxJS v5, where certain events can trigger the schedule to reload. Currently using 3 sources - schedule$, event$, and userNotification$ (example below).

I've tried a number of different strategies and I'm consistently getting weirdness like recursive reloads when the reloadSchedule event time hits. Is there a way for downstream data (event$) to cleanly trigger upstream (schedule$) reloads, without any actions/notifications lingering from previous schedule items?

schedule$ = new Rx.BehaviorSubject(
  {schedule:[
    {start:'1pm', end:'2pm', action:'sayhi'},
    {start:'2pm', end:'3pm', action:'sayhi'},
    {start:'3pm', end:'3pm', action:'reloadSchedule'},
    {start:'3:01pm', end:'4pm', action:'sayhi'},
  ]}
);

function loadSchedule(){
  somethingAsync.then((moreData)=>schedule$.next(moreData));
}

event$ = schedule$.flatMap((data)=>{
  return Rx.Observable
    .from(data.schedule)
    .flatMap((event)=>{
      return Rx.Observable.timer(event.start)
      .flatMap(()=>{
        // do actions here once previous actions/notifications finish
        if(event.action === 'reloadSchedule'){
          loadSchedule()
        }
        return Rx.Observable.of(someUserMessage);
      })
    })
})

userNotification$ = Rx.Observable.timer(1000).withLatestFrom(event$)
.flatMap((someUserMessage)={
  // fade message after 5 seconds
});

userNotification.subscribe(()=>{});
Adam
  • 2,873
  • 3
  • 18
  • 17
  • 1
    What is schedule$ and how does it differ from scheduleData$? – paulpdaniels Mar 15 '16 at 16:32
  • Thanks for asking Paul. I fixed the variable names. Also came up with a solution that works (not necessarily the cleanest, but works). Posting it as an example for others. – Adam Mar 26 '16 at 15:50

1 Answers1

0

Ended up figuring out a solution. There may be cleaner ways to do it, but it worked.

Basic idea is to have one timer that controls the actions. Compare the event times to that timer to get the correct current event. Unsubscribe when it's time to reload.

Rough example.

// start and end are ISO strings - showing 1pm etc.
let schedule$ = new Rx.BehaviorSubject([
  {start:'1pm', end:'2pm', action:'sayhi'},
  {start:'2pm', end:'3pm', action:'sayhi'},
  {start:'3pm', end:'3pm', action:'reloadSchedule'},
  {start:'3:01pm', end:'4pm', action:'sayhi'},
]);

schedule$.subscribe((sched)=>{
  new Scheduler(sched)
});

function loadSchedule(){
  somethingAsync.then((moreData)=>schedule$.next(moreData));
}

class Scheduler{
  constructor(schedule){
    let notificationsCleared = true;
    let sliced;
    let event$ = Rx.Observable
      .timer(1000)
      .filter(()=>notificationsCleared)
      .map(()=>{
        let now = (new Date()).toISOString();
        sliced || (sliced = schedule.slice(0));
        while (now > sliced[0].end){
          sliced.shift();
        }
        return sliced[0];
      }).share();

    let cleanup$ = event$.filter((evt)=>evt.action === 'reloadSchedule')

    let userNotification$ = event$.map(()=>{
      notificationsCleared = false;
      someAsyncNotification()
      .then(()=>notificationsCleared = true)
    });

    let userSub = userNotification.subscribe(()=>{});
    let cleanupSub = cleanup$.subscribe(()=>{
      loadSchedule();
      userSub.unsubscribe();
      cleanupSub.unsubscribe();
    });
  }
};
Adam
  • 2,873
  • 3
  • 18
  • 17