Sweetalert: Menangani peringatan manis yang tertunda

Dibuat pada 5 Okt 2015  ·  15Komentar  ·  Sumber: t4t5/sweetalert

EDIT: Silakan lihat komentar saya nanti untuk SwalService dan pedoman terbaru

Saya tahu ini harus menjadi permintaan tarik. Tapi saya ingin menambahkan pembungkus yang saya tulis di sini sehingga saya bisa mendapatkan umpan balik jika ini adalah tambahan yang berguna.

Penggunaan ini di sini adalah bahwa di mana saja di aplikasi Anda, Anda dapat memanggil swalService.swal() dan jika ada peringatan manis terbuka, itu akan mengantrekannya dan menempatkan pemberitahuan pada peringatan manis saat ini bahwa ada peringatan yang tertunda. Metode swal akan mengembalikan pengidentifikasi unik sehingga Anda dapat memanggil close pada sweet alert tertentu meskipun tertunda.

var _ = require('underscore');

var swalService = {
  pendingSwal: [],
  currentSwal: null,
  swalFirstCalled: false,
  __swal: require('sweetalert'),

  swal: function() {
    var pending = {
      args: arguments,
      id: _.uniqueId()
    }
    if (this.isSwalOpen()) {
        this.pendingSwal.push(pending);
    } else {
      this.__swal.apply(null, pending.args);
      this.currentSwal = pending;
      if (!this.swalFirstCalled) {
        $('.sweet-alert').prepend('<span class="other-messages"></span>');
        this.swalFirstCalled = true;
      }
    }
    this.refreshPendingText();
    return pending.id;
  },

  refreshPendingText: function() {
    if (_.isEmpty(this.pendingSwal)) {
      $('.other-messages').text('');
    } else {
      $('.other-messages').text(_.size(this.pendingSwal) + ' unread alerts');
    }
  },

  close: function(id) {
    if (_.isUndefined(id) || (this.currentSwal && this.currentSwal.id == id)) {
      this.__swal.close();
    } else if (!_.isUndefined(id) && !_.isEmpty(this.pendingSwal)) {
      var indexOfSwalToClose;
      for (var i = 0; i < this.pendingSwal.length; i++) {
        if (this.pendingSwal[i].id == id) {
          indexOfSwalToClose = i;
          break;
        }
      }
      if (!_.isUndefined(indexOfSwalToClose)) {
        this.pendingSwal.splice(indexOfSwalToClose, 1);
        this.refreshPendingText();
      }
    }
  },

  onCloseOfCurrentSwal: function() {
    swalService.currentSwal = null;
    if (_.size(swalService.pendingSwal) > 0) {
      var pending = swalService.pendingSwal.shift();
      swalService.swal.apply(swalService, pending.args);
    }
  },

  isSwalOpen: function() {
    return !_.isUndefined(this.currentSwal) && !_.isNull(this.currentSwal);
  },

  setSwalDefaults: function() {
    this.__swal.setDefaults({});
    var originalClose = this.__swal.close;
    this.__swal.close = function() {
      originalClose();
      setTimeout(_.bind(swalService.onCloseOfCurrentSwal, swalService), 400);
    };
  }

};

Semua 15 komentar

sayang sekali ini bukan perilaku default ketika ada beberapa pemberitahuan swal :/
Ini akan menjadi PR yang bagus.

@kentmw Apa kemungkinan Anda membuat rilis baru dengan perbaikan ini di dalamnya, jadi mungkin untuk menangani beberapa Swal-popup setelah satu sama lain?
Mungkin bukan sebagai PR, karena kemungkinan besar mereka tidak akan digabungkan, tetapi mungkin panduan, tentang cara menggunakan kode di atas sebagai gantinya? Apakah hanya salin/tempel ke file SWAL js?

@inctor Saya akan menulis panduan dalam sekitar 15 menit ke depan dan memperbarui layanan ke yang saat ini saya gunakan untuk menghapus beberapa bug asli.

Layanan Swal

Berikut adalah kode dengan hanya jquery sebagai dependensi proyek selain sweetalert:

Kode

var SwalService = function(options) {
  this.pendingSwal = [];
  if (options && options.showPendingMessage != undefined) {
    this.showPendingMessage = options.showPendingMessage;
  }
  this.initialize();
}

SwalService.prototype = {
  currentSwal: null,
  showPendingMessage: true,
  swalFirstCalled: false,
  __swal: swal,
  pendingSwal: null,
  nextId: 1,

  swal: function() {
    var pending = {
      args: arguments,
      id: this.nextId++
    }
    return this._swalWithId(pending);
  },

  _swalWithId: function(pending) {
    var service = this;
    if (this.isSwalOpen() || this.isClosing) {
      this.pendingSwal.push(pending);
    } else {
      this.__swal.apply(null, pending.args);
      this.currentSwal = pending;
      if (!this.swalFirstCalled) {
        $('.sweet-alert').prepend('<span class="other-messages"></span>');
        this.swalFirstCalled = true;
      }
    }
    this.refreshPendingText();
    return pending.id;
  },

  onClosed: function() {
    this.isClosing = false;
    this.openNextSwal();
  },

  refreshPendingText: function() {
    if (this.showPendingMessage) {
      if (this.pendingSwal.length === 0) {
        $('.other-messages').text('');
      } else {
        $('.other-messages').text(this.pendingSwal.length + ' unread alerts');
      }
    }
  },

  close: function(id) {
    if (id === undefined || (this.currentSwal && this.currentSwal.id == id)) {
      this.__swal.close();
    } else if (id !== undefined && this.pendingSwal.length > 0) {
      var indexOfSwalToClose;
      for (var i = 0; i < this.pendingSwal.length; i++) {
        if (this.pendingSwal[i].id == id) {
          indexOfSwalToClose = i;
          break;
        }
      }
      if (!(indexOfSwalToClose === undefined)) {
        this.pendingSwal.splice(indexOfSwalToClose, 1);
        this.refreshPendingText();
      }
    }
  },

  openNextSwal: function() {
    var service = this;
    if (service.pendingSwal.length > 0) {
      var pending = service.pendingSwal.shift();
      service._swalWithId(pending);
    }
  },

  isSwalOpen: function() {
    return this.currentSwal != null && this.currentSwal != undefined;
  },

  closeAndFireCallback: function(id, opts) {
    this.close(id);
    if (this.currentSwal.args && this.currentSwal.args.length > 1 && typeof this.currentSwal.args[1] == 'function') {
      // Currently, programatically closing the swal doesn't invoke the callback.
      var callback = this.currentSwal.args[1];
      callback(opts);
    }
  },

  initialize: function() {
    var service = this;
    var originalClose = this.__swal.close;
    this.__swal.close = function() {
      service.isClosing = true;
      originalClose();
      service.currentSwal = null;
      setTimeout(function() {
        service.onClosed();
      }, 400);
    };
  }
}

Bawa kode ini sesuka Anda setelah sweetalert - jika Anda menggunakan browserify, tambahkan saja

 module.exports = SwalSevice;

di bagian bawah file.

Inisialisasi

Setelah berada di halaman, inisialisasi layanan:

var swalService = new SwalService();

Catatan: belum diuji dengan beberapa contoh pada halaman yang sama. Untuk sebagian besar penggunaan, singleton adalah yang Anda inginkan.

Buat Seperti Biasa

Untuk membuat peringatan manis, gunakan metode swal layanan persis seperti Anda menggunakan metode swal asli dari sweetalert.

var handleId = swalService.swal('My Title', 'My message', 'info');
//or
var handleId = swalService.swal({title: 'My Title', text: 'My message', type: 'info'}, function(args) { ... });

Silakan, dan coba dengan menyalin kode layanan ke konsol di http://t4t5.github.io/sweetalert/
Tapi sekarang, jika Anda menembakkan swal lain setelahnya, alih-alih menimpanya, swal baru akan ditunda dan sebuah pesan muncul.

Menutup

Anda dapat menutup swal saat ini melalui UI atau secara terprogram menggunakan swalService.close() . Ini akan menutup swal saat ini dan membuka swal berikutnya setelah penundaan singkat (400ms) hingga animasi penutupan selesai. Karena metode swal swalService mengembalikan pegangan id yang unik, Anda dapat menutup swal tertentu (bukan hanya yang sekarang) dengan menggunakan swalService.close(swalHandleId) bahkan jika swal ke target tertunda. Ini juga berguna jika Anda memiliki swal yang tidak ingin ditutup oleh pengguna seperti indikasi pemuatan/penundaan yang tidak memiliki tombol tutup namun pengembang dapat menutupnya secara terprogram.

Harap dicatat bahwa ketika Anda memiliki panggilan balik yang ditambahkan ke peringatan Anda yang harus dipanggil setelah penutupan, panggilan balik ini akan secara otomatis dipanggil jika pengguna memulai penutupan. Tetapi jika Anda ingin memanggil panggilan balik ini sambil menutup peringatan secara terprogram, panggil:

swalService.closeAndFireCallback(id, opts)
// opts will be passed to the callback
// id is an optional identifier for the targeted alert. Defaults to current swal

Saya yakin ini dapat ditangani secara otomatis tanpa memerlukan metode terpisah (selain .close), tetapi saya belum memfaktorkannya kembali.

Terbuka

Layanan ini juga memiliki sedikit lebih banyak untuk API. Anda dapat menghubungi swalService.isSwalOpen() untuk melihat apakah saat ini ada swal terbuka.

Pesan Peringatan Tertunda

Sebuah pesan tentang jumlah swal yang tertunda akan muncul di swal saat ini saat mereka mengantri. Anda dapat mengatur gaya ini dengan menambahkan css yang menargetkan rentang dengan kelas "pesan lain".

.other-messages {
  color: red;
}

Anda juga dapat mematikan semua pesan yang tertunda dengan menginisialisasi layanan dengan:

var swalService = new SwalService({showPendingMessage: false})

Jelas, status layanan ini tidak mendukung i18n (pemirsa multibahasa), Anda harus mengganti metode refreshPendingText() untuk itu.

Tangkapan

Jika Anda tidak membuat swal dengan benar, seperti judul yang hilang misalnya, swalService akan tetap berpikir ada peringatan terbuka meskipun perpustakaan swal dasar tidak pernah membuatnya. Berhati-hatilah untuk sepenuhnya membangun peringatan Anda.

@kentmw Terima kasih banyak. Memperbaiki masalah saya karena perlu menyajikan peringatan satu demi satu.

Tampaknya tidak berfungsi jika Anda mencoba dan mengikat dua swal, yang masing-masing mengharuskan pengguna mengklik "ok" untuk melanjutkan (dan bukan "membatalkan") - swal kedua ditampilkan, tetapi kemudian segera ditutup

@QuakePhil apakah Anda keberatan memposting permintaan swalService.swal berurutan?

Sebenarnya, saya membuatnya bekerja dengan menyarangkan swal ke-2 di callback yang pertama, dan menyetel closeOnConfirm ke false di yang pertama... (solusi ini berfungsi tanpa perlu swalservice, menggunakan swal2)

Kode ternyata agak kering, karena persyaratan bersarang (jadi saya tidak bisa begitu saja membuka swal baru di panggilan balik, panggilan balik itu sendiri harus berupa panggilan langsung ke swal, atau mungkin ada cara untuk memiliki fungsi perantara antara dua angsa; saya hanya belum menemukan jawabannya)

@kentmw kamu pria yang luar biasa!! Terima kasih banyak!!

Pembungkusmu menyelamatkan pantatku. Beberapa catatan. Seperti yang disebutkan @QuakePhil, ada masalah jika ada beberapa peringatan dalam antrean, masing-masing dengan respons bersarang untuk konfirmasi/pembatalan.

Untuk mengatasi ini saya menutup swal induk menggunakan ID segera setelah anak dibuat. Dan untuk memasangkan skenario Induk (pertanyaan) - Anak (respons) ini, saya telah membuat sedikit modifikasi di pembungkus untuk menambahkan semua swals baru di awal larik/antrian dan bukan di akhir.

Ini berfungsi dengan permintaan tunggal juga. Jadi, pertimbangkan skenario berikut untuk menunjukkan bagaimana lansiran dibuat:

ID: 1, NAME: swallQA, CONTENT: Would you like to delete this file A? (Confirm/Cancel)
ID: 2, NAME: swallQB, CONTENT: Would you like to delete this file B? (Confirm/Cancel)
ID: 3, NAME: swallCA, CONTENT: Confirmed - delete A
ID: 4, NAME: swallCB, CONTENT: Cancelled - won't delete B

Dan berikut adalah bagaimana lansiran akan ditampilkan kepada pengguna:

ID: 1, NAME: swallQA, CONTENT: Would you like to delete this file A? (Confirm/Cancel)
ID: 3, NAME: swallCA, CONTENT: Confirmed - delete A
ID: 2, NAME: swallQB, CONTENT: Would you like to delete this file B? (Confirm/Cancel)
ID: 4, NAME: swallCB, CONTENT: Cancelled - won't delete B

Jika Anda memiliki pertanyaan, beri tahu saya.

Sekali lagi terima kasih banyak, bungkusnya melakukan pekerjaan yang luar biasa.

@koullislp Saya senang itu berguna :) Apakah Anda keberatan memposting modifikasi Anda? Saya akan memperbarui posting asli saya setelah melihatnya.

@kentmw

Hanya satu kata yang diubah dalam kode Anda:

<       this.pendingSwal.push(pending);
---
>       this.pendingSwal.unshift(pending);

Dan cara saya menyebutnya:

var handleId = swalService.swal({
        title: "Are you sure?",
        text: "You are about to delete file"+filename,
        type: "warning",
        showCancelButton: true,
        confirmButtonText: "Confirm",
        cancelButtonText: "Cancel",
        closeOnConfirm: false
    }, function(isConfirm) {
        if (isConfirm) {
            sendRequest("POST", "", "delete", function(actionResult) {
                var handleSecondId = swalService.swal({
                    title: "Result", 
                    text: "deleted!"
                });
                swalService.closeAndFireCallback(handleId);
            }
        }
    });

Adakah kemungkinan kalian dapat membantu saya membuat konsep ini menggunakan janji? Saya telah menggunakan ini dengan https://github.com/limonte/sweetalert2 , tetapi penulis merasa antrian peringatan adalah "spam" (https://github.com/limonte/sweetalert2/issues/125). Namun, ini adalah solusi sempurna untuk kasus penggunaan saya, dan saya tidak cukup akrab dengan janji untuk mencari cara membuat dan menyelesaikannya menggunakan fork of sweetalert dan addon Anda. Saya kira saya bisa menambahkan then(function(){}) dan meletakkan resolve() dan close() di sana, tetapi saya tidak tahu apakah itu akan benar-benar berfungsi. Sekali lagi, saya belum terlalu paham tentang janji.

Ada saran? Pada dasarnya, saya perlu cara untuk menggunakan ini dengan janji alih-alih fungsi panggilan balik.

SweetAlert2 mendukung antrian modals: https://sweetalert2.github.io/#chaining -modals

Terima kasih banyak kawan, kamu luar biasa!

@kentmw kode swalservice itu luar biasa, terima kasih banyak (saya tahu swal2.0 memperbaiki ini, tetapi saya sengaja tetap menggunakan 1.0 karena saya merasa lebih sederhana dan lebih baik untuk digunakan, dan juga memiliki beberapa fitur yang dihapus di 2.0 )

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

mouro001 picture mouro001  ·  3Komentar

fracz picture fracz  ·  4Komentar

mateuszjarzewski picture mateuszjarzewski  ·  4Komentar

rafatux picture rafatux  ·  5Komentar

Untit1ed picture Untit1ed  ·  5Komentar