點燈坊

失くすものさえない今が強くなるチャンスよ

SweetAlert2 之 Error Handling

Sam Xiao's Avatar 2020-07-31

一般來說呼叫 API 的 Asynchronous 才會遇到 Promise,也才需要 Error Handling,但 SweetAlert2 按下 Confirm 時回傳 Fulfilled Promise,按下 Cancel 時回傳 Rejected Promise,此時會進入處理 API 的 Error Handling,這該如何解決呢 ?

Version

macOS Catalina 10.15.6
WebStorm 2020.2
Ramda 0.27.0
Vue 2.6.11
SweetAlert 6.11.4

Promise Chain

<template>
  <div>
    <button class="btn btn-primary" @click="onSubmit">Submit</button>
    {{ msg }}
  </div>
</template>

<script>
import swal from 'sweetalert2'
import axios from 'axios'

let fetchBook = x => axios.get(`http://localhost:3000/books/${x}`)
  .then(x => x.data)

let onSubmit = function() {
  let errorHandling = e => {
    if (e === 'cancel') {}
    else if (e.response)
      console.log(e.response.status)
    else
      console.log(e)
  }

  swal({
    title: 'Are you sure?',
    type: 'warning',
    showCancelButton: true,
    confirmButtonClass: 'btn btn-success btn-fill',
    cancelButtonClass: 'btn btn-danger btn-fill',
    confirmButtonText: 'Confirm',
    buttonsStyling: false
  }).then(() => 1)
    .then(fetchBook)
    .then(x => this.msg = x.title)
    .catch(errorHandling)
}

export default {
  name: 'App',
  data: () => ({
    msg: ''
  }),
  methods: {
    onSubmit
  }
};
</script>

25 行

swal({
  title: 'Are you sure?',
  type: 'warning',
  showCancelButton: true,
  confirmButtonClass: 'btn btn-success btn-fill',
  cancelButtonClass: 'btn btn-danger btn-fill',
  confirmButtonText: 'Confirm',
  buttonsStyling: false
}).then(() => 1)
  .then(fetchBook)
  .then(x => this.msg = x.title)
  .catch(errorHandling)

SweetAlert 的 swal() 回傳 Promise,若按下 Confirm 接著要打 API,因此可在 .then() 之後呼叫 fetchBook()

16 行

let errorHandling = e => {
  if (e === 'cancel') {}
  else if (e.response)
    console.log(e.response.status)
  else
    console.log(e)
}

當按下 cancel 時,swal() 會回傳 Rejected Promise,因此進入 .catch()errorHandling()

關鍵在於按下 cancel 時,Rejected Promise 內部值為 cancel,因此可藉此判斷是來自於 swal() 的 Rejected Promise,還是來自於 axios.get() 的 Rejected Promise。

Ramda

<template>
  <div>
    <button class="btn btn-primary" @click="onSubmit">Submit</button>
    {{ msg }}
  </div>
</template>

<script>
import swal from 'sweetalert2'
import axios from 'axios'
import { pipe, andThen as then, otherwise, always } from 'ramda'

let fetchBook = x => axios.get(`http://localhost:3000/books/${x}`)
  .then(x => x.data)

let onSubmit = function() {
  let swalBody = {
    title: 'Are you sure?',
    type: 'warning',
    showCancelButton: true,
    confirmButtonClass: 'btn btn-success btn-fill',
    cancelButtonClass: 'btn btn-danger btn-fill',
    confirmButtonText: 'Confirm',
    buttonsStyling: false
  }

  let errorHandling = e => {
    if (e === 'cancel') {}
    else if (e.response)
      console.log(e.response.status)
    else
      console.log(e)
  }

  pipe(
    swal,
    then(always(1)),
    then(fetchBook),
    then(x => this.msg = x.title),
    otherwise(errorHandling)
  )(swalBody)
}

export default {
  name: 'App',
  data: () => ({
    msg: ''
  }),
  methods: {
    onSubmit
  }
};
</script>

36 行

pipe(
  swal,
  then(always(1)),
  then(fetchBook),
  then(x => this.msg = x.title),
  otherwise(errorHandling)
)(swalBody)

既然 swal() 回傳為 Promise,因此可直接在 Ramda 的 pipe() 內使用 swal(),讓 swal()fetchBook() 一起 Function Pipeline。

Error handling 部分則完全一樣。

Conclusion

  • 遇到有 function 回傳 Rejected Promise 時不用擔心,只要清楚知道 Rejected Promise 內部值為何,就可以加以判斷與 axios.get() 的 Rejected Promise 分開處理