2017-01-29 1 views
0

У меня это работает отлично для меня, если страница остается статической, как показано ниже.Как бы я реорганизовал этот угловой 2 наблюдаемый, чтобы не дублировать при изменении маршрута

Используя услугу, чтобы получить результаты HTTP вызова по таймеру повторить

this.lts.getEventDetails(link,currentTime) 
    .subscribe(res=>{ 
    this.rs.setCurrentRace(activeRound['uid'],res.S); 
    }) 

Что вызывает эту функцию в моей службе

getEventDetails(liveTimingLink:string,time:number){ 

    let link = `${liveTimingLink}?R=${time}` 
    let timer = 5000; 

    Observable 
    .interval(timer) 
    .flatMap(() => { 
     return this.http.get(link) 
     .map(res=>{return res.json()}) 
    }) 
} 

Проблема в том, что просто дублирует таймер наблюдаемым каждый время изменения маршрута и вернуться.

Я не уверен, как я должен справиться с этим, я думал, что установил бы наблюдаемую переменную в сервисе и просто вернул бы ее, но я не знаю, как бы я это сделал.

Или я должен делать это так, как будто я делаю это, но просто отменил подписку по мере изменения маршрута? Опять же, я не знаю, как это сделать.

Любые идеи совета очень приветствуются. Спасибо, ребята

ответ

1

Ваша идея создания наблюдаемого вне вызова метода хороша.

BUT ... Каждый .subscribe() наблюдаемый получает вызывает новое выполнение наблюдаемого.

Это означает, что недостаточно одного экземпляра наблюдаемого. Вам также необходимо, чтобы делить исполнение среди всех подписчиков.

Первоначально я думал, что вы могли бы использовать оператор .share(), но она будет делиться только наблюдаемую до тех пор, как он имеет, по меньшей мере, один абонент. Это не будет работать в вашем случае, так как наблюдаемый теряет своего единственного абонента, когда пользователь покидает страницу. В следующий раз, когда пользователь посещает страницу, наблюдаемый должен повторно запускаться с нуля (другими словами, сбрасывается интервал). Я подозреваю, что это не то, что вы хотите.

Я нашел решение, которое использует оператор .publish() для совместного использования наблюдаемого, и .connect(), чтобы начать испускать значения при первом извлечении. Интервал продолжает работать независимо от того, подписан ли вы на него или нет.

Проверьте это Plunkr, чтобы увидеть его в действии. Кнопки subscribe/unsubscribe реплицируют то, что происходит, когда пользователь переходит к странице/от нее. Откройте консоль браузера, чтобы просмотреть значения, полученные подписчиком.

Код для службы:

@Injectable() 
class MyService { 
    // Create the interval once and share it among all subscribers. 
    source = Observable.interval(1000).publish(); 
    intervalStarted = false; 

    getEventDetails(param) { 
    // The first time the observable is retrieved, 
    // connect to it (= make it start emitting values). 
    if (!this.intervalStarted) { 
     this.source.connect(); 
     this.intervalStarted = true; 
    } 

    // Here, continue transforming the original observable using operators like mergeMap(). 
    return this.source.map(val => `${val} - ${param}`); 
    } 
} 

Несколько незначительных замечаний по поводу вашей версии метода getEventDetails():

  • Вы можете уронить { } вокруг тела ваших функций стрелок. Таким образом, вы получите неявный return, и ваш код будет более компактным. Однако вы можете сохранить свою версию для удобства чтения.
  • Если вы используете Angular2 +, вы используете RxJS 5, а «официальный» - mergeMap().flatMap() происходит от RxJS 4 и является просто псевдонимом для mergeMap().
  • Поскольку локальные переменные в методе не изменяются, вы можете объявить их с const против let.
  • Почему нет return перед Observable.interval?

Вот переписан метод:

getEventDetails(liveTimingLink:string, time:number){ 

    const link = `${liveTimingLink}?R=${time}`; 
    const timer = 5000; 

    return Observable 
    .interval(timer) 
    .flatMap(() => this.http.get(link).map(res => res.json())) 
} 
0

Я вернулся к этому и ценю ваши мысли по этому вопросу и советам, я всегда высоко ценю обратную связь от более опытного кодера.

В результате я переработал код, чтобы просто отказаться от подписки на наблюдаемое при изменении маршрута. Показалось проще и заботился о моих потребностях

Услуга:

getEventDetails(liveTimingLink:string,time:number){ 

    const link = `${liveTimingLink}?R=${time}` 
    const timer = 5000; 

    return Observable 
    .interval(timer) 
    .flatMap(() => { 
     return this.http.get(link) 
     .map(res=>{return res.json()}) 
    }) 
    } 

Компонент:

saveLiveRaceString(serie:FirebaseObjectObservable<any>,activeRound){ 

    /** 
    Only map & subscribe if current event has begun. 
    **/ 

    const currentUnix = moment().unix(); 

    if(currentUnix > activeRound['mainEventUnix']){ 

    this.eventSubscription = this.lts.getEventDetails(serie['liveTimingLink'],currentUnix) 
     .subscribe(res=>{ 
     this.rs.setCurrentRace(activeRound['uid'],res.S); 
     }) 
    } 

} 

ngOnDestroy() { 

    /** 
    Unsubscribe from the event observable 
    **/ 

    this.eventSubscription?this.eventSubscription.unsubscribe():null 
} 
Смежные вопросы