2017-01-16 8 views
4

В моем компоненте детали клиента у меня есть следующий код, который достигает того, что мне нужно, но не в реактивном/наблюдаемом способе, я думаю, это возможно.Используя Observables, покажите индикатор загрузки после задержки, но отмените, если загрузка завершена вовремя?

Вместо того, чтобы обертывать this.isLoading = true; в инструкции if, есть ли способ сделать это с использованием методов реактивного программирования? Возможно, отменив/отбросив задержанную наблюдаемую, если клиент будет извлечен первым? Или я об этом неправильно?

export class CustomerDetailComponent implements OnInit { 

    customer: Customer; 
    errorMessage: string; 
    isLoading: boolean; 

    constructor(
    private customerService: CustomerService, 
    private route: ActivatedRoute, 
    private router: Router, 
    private location: Location 
) { } 

    ngOnInit() { 
    let idParam = this.route.params 
     .distinctUntilChanged(params => params['id']); 

    idParam.subscribe(params => 
    { 
     this.errorMessage = ''; 
    }); 

    idParam.delay(300).subscribe(params => 
    { 
     if (!(this.customer && this.customer.id == params['id'])) 
     this.isLoading = true; 
    }); 

    idParam.switchMap((params: Params) => this.customerService.getCustomer(params['id'])) 
     .subscribe(customer => 
     { 
     this.customer = customer; 
     this.isLoading = false; 
     }, 
     error => this.errorMessage = error); 
    } 
} 

ответ

3

Вы можете написать что-то вдоль этих линий:

function getCustomer(id) { 
    return Observable.of({'name': 'John', id}).delay(500); 
} 

Observable.of({'id': 42}) 
    .distinctUntilChanged(params => params['id']) 
    .do(() => { 
     // this.errorMessage = ''; 
    }) 
    .switchMap((params) => { 
     return Observable.combineLatest(
      Observable.of(true).delay(300).startWith(null), // delay Observable 
      getCustomer(params['id']).startWith(null), // customer Observable 
      function(delay, customer) { // selector function 
       if (customer) { 
        return customer; 
       } 

       if (delay && !customer) { 
        console.log('this.isLoading = true;'); 
       } 
       return null; 
      }) 
      .filter(customer => customer) 
      .distinctUntilChanged(customer => customer['id']); 
    }) 
    .subscribe(
     customer => { 
      console.log('this.isLoading = false;'); 
      console.log(customer); 
      // this.customer = customer; 
     }, 
     error => { 
      // this.errorMessage = error; 
     } 
    ); 

Смотреть демо: https://jsbin.com/nebutup/5/edit?js,console

Внутренний combineLatest() получает два Наблюдаемые:

  1. В 300мс оттянуть
  2. Клиент f (в этом демо-моделировании)

Тогда есть также функция проецирования, используемая для выбора того, что мы хотим распространять дальше. Оба Observables используют .startWith(null), чтобы удостовериться, что у них есть хотя бы один элемент, поэтому combineLatest() будет вызван изменением любого из них. Тогда мы можем легко узнать, была ли первая наблюдаемая, которая испускалась, задержкой или клиентом.

Тогда есть также filter() удалить все null значения и distinctUntilChanged(), чтобы убедиться, что мы не испускают тот же клиент дважды (это обрабатывает случай, когда клиент завершает первый).

Затем, когда мы запустим эту демку и задержка срабатывает первый выход следующее:

this.isLoading = true; 
this.isLoading = false; 
{ name: 'John', id: 42 } 

Это означает, что мы сначала покажем загрузку, а затем скрыть его.

Затем, когда мы изменяем getCustomer() завершить первый:

function getCustomer(id) { 
    return Observable.of({'name': 'John', id}).delay(100); 
} 

мы получим следующее:

this.isLoading = false; 
{ name: 'John', id: 42 } 

Это означает, что мы никогда не показывают никакой нагрузки.

+0

Это намного чище, чем мой код, спасибо. Однако у меня есть задержка перед установкой this.isLoading = true, и мой вопрос заключается в том, как отменить его, если this.customerService.getCustomer заканчивается первым - можете ли вы помочь с этим? – Dean

+0

@ Dean Ах, я вижу, что вы собираетесь делать. Я обновил свой ответ. – martin