讓刪除確認通吃confirm及jQuery.Deferred
3 |
最近在寫的元件有個「彈出對話框經使用者確認再刪除」的需求,原本是小事一椿,但之前介紹過使用自訂確認對話框取代window.confirm的技巧已廣泛應用在專案裡,某些時候也可能只用window.confirm就打發,問題就變複雜了。
二者最大的差異是前者($.kendoConfirm)為非同步執行,刪除動作需放在jQuery Deferred.promise()的done()方法;window.confirm則為內建同步指令,瀏覽器會等待使用者回應才往下執行,故用 if 判斷 true/false 決定是否刪除即可。
以下程式可看出兩種做法的差異:線上展示 (關於 $.kendoConfirm 的說明請參考舊文)
$(function() {
function deleteConfirm_Kendo() {
return $.kendoConfirm("刪除確認", "是否確定要刪除?");
}
function deleteConfirm_Native() {
return confirm("是否確定要刪除?");
}
$("#btnTest1").click(function() {
deleteConfirm_Kendo().done(function() {
alert("刪除");
});
});
$("#btnTest2").click(function() {
if (deleteConfirm_Native()) {
alert("刪除");
}
});
});
要讓元件好用,最理想的做法是大小通吃:若確認函式傳回true/false就用 if 同步執行;若傳回jQuery Promise就用.done()非同步執行。
例如:線上展示
$(function() {
function deleteConfirm_Kendo() {
return $.kendoConfirm("刪除確認", "是否確定要刪除?");
}
function deleteConfirm_Native() {
return confirm("是否確定要刪除?");
}
function execDeleteAction() {
alert("刪除");
}
function doDelete(deleteConfirm) {
var res = deleteConfirm();
//若函式傳回Promise, 放入done()中執行
if (res && res.hasOwnProperty("done"))
res.done(execDeleteAction);
//若函式傳回boolean,由傳回結果決定resolve或reject
else if (res)
execDeleteAction();
}
$("#btnTest1").click(function() {
doDelete(deleteConfirm_Kendo);
});
$("#btnTest2").click(function() {
doDelete(deleteConfirm_Native);
});
});
以上寫法有個小缺點,執行刪除的部分必須抽出來變成函式,分於兩處呼叫。
針對這個缺點,額外加個jQuery.Deferred串場就能克服:線上展示
function doDelete(deleteConfirm) {
var dfd = jQuery.Deferred();
var promise = dfd.promise();
var res = deleteConfirm();
//若函式傳回Promise, 替換原有Promise
if (res && res.hasOwnProperty("done"))
promise = res;
//若函式傳回boolean,由傳回結果決定resolve或reject
else if (res)
dfd.resolve();
else
dfd.reject();
promise.done(function() {
alert("刪除")
});
}
兩種做法都能讓刪除確認程序通吃window.confirm及jQuery.Deferred,擇一而用即可,以上提供大家參考。
Comments
# by Ammon
何不直接在 deleteConfirm_Native 回傳 deferred 物件? 可以省下if判斷
# by Jeffrey
to Ammon, 在我的案例中,deleteConfirm_Native相當於呼叫端提供的Callback參數,對於從來沒學過jQuery Deferred的開發者,Callback函式只需return true或false,降低元件使用的門檻。
# by Peter Tsai
最後一個例子的 promise 物件會被 res 蓋掉而變成另一個函示回傳的 promise 物件,這兩個 promise 畢竟是在執行時期才進行判斷,反而增加程式複雜度,提升了使用者偵錯的門檻。為了省下一個 function 而改用 defer 技巧我是覺得有點 over design 了。 :p