[Vue-rx] Disable Buttons While Data is Loading with RxJS and Vue.js

Streams give you the power to handle a "pending" state where you've made a request for data, but the data hasn't yet returned. You can leverage this pending stream to update your template as well which is often displayed as a "loader" or disabling some part of the UI.

 

<template>
  <section class="section">
    <button class="button" :disabled="disabled$" v-stream:click="click$">{{buttonText$}}</button>
    <h2>
      {{name$}}
    </h2>
    <img v-stream:error="imageError$" :src="image$" alt="">
  </section>
</template>

<script>
import { from, of, merge, throwError } from 'rxjs';
import {
  switchMap,
  pluck,
  map,
  mapTo,
  catchError,
  shareReplay,
  share,
  startWith
} from 'rxjs/operators';

export default {
  name: 'app',
  domStreams: ['click$', 'imageError$'],
  subscriptions() {
    const createLoader = url => from(this.$http.get(url)).pipe(pluck('data'));

    const luke$ = this.click$.pipe(
      mapTo('https://starwars.egghead.training/people/1'),
      switchMap(createLoader),
      catchError(() => of({name: 'Failed.. :('})),
      share()
    );

    const name$ = luke$.pipe(pluck('name'));

    const loadImage$ = luke$.pipe(
      pluck('image'),
      map(src => `https://starwars.egghead.training/${src}`)
    );

    const failImage$ = this.imageError$.pipe(
      mapTo(`http://via.placeholder.com/400x400`)
    );

    const image$ = merge(
      loadImage$,
      failImage$
    )

    const disabled$ = merge(
      this.click$.pipe(mapTo(true)),
      luke$.pipe(mapTo(false)),
    ).pipe(startWith(false));

    const buttonText$ = disabled$.pipe(map(b => (b ? 'Loading...' : 'Load')));


    return {
      name$,
      image$,
      failImage$,
      disabled$,
      buttonText$
    };
  }
};
</script>

 

posted @ 2018-07-18 19:46  Zhentiw  阅读(421)  评论(0编辑  收藏  举报