Comments 22
Плюс, вы никак не сделаете замену confirm() на кастомных окошках. Вот вообще никак, т.к. всплывающие html-окна не будут блокировать исполнение кода. То, что реализовано в статье — обычный callback.
Максимально приближенный вариант будет что-то вроде:
async function() { // Здесь выполняется наш код. Да, в async
if (await jdDialog(...)) { // Ваша функция должна вернуть true
...
}
}
Но такое поведение будет доступно только если вы реализуете промисы и только в async-функциях, само-собой.
P.S. Советую взглянуть на библиотеку noty js
Это то, что вам нужно, только с бОльшими возможностями.
Не делайте так :) Если кто-то будет потом поддерживать этот код, он повесится. Дважды, как и код.
Поскольку заблокировать выполнение в JS не получится, вы решили «перекликивать» элемент. Это ужасное решение.
1. Что если на клике висят и другие обработчики событий?
2. Что если до if (jdDialog) есть каокй-то код?
В обоих случаях код будет выполнен дважды.
А если нужно вызвать диалог без клика? Ну и т.д.
Для более сложных алгоритмов естественно уже не подходит. Хотя и тут можно найти решение. Например по другому селектору инициировать клик. Здесь сознательно я иду на повторное выполнение кода, поэтому на этот факт придётся оглядываться.
Ещё раз повторяю, найденное решение — для определённой ниши задач.
let $link = $('a#some-link');
$link.on('click', async function() {
if (await showMessageBox('Текст сообщения')) {
console.log('Согласен');
} else {
console.log('Не согласен');
}
});
function showMessageBox(text) {
let defer = new $.Deferred();
let n = new Noty({
text: text,
timeout: false,
type: 'alert',
layout: 'center',
closeWith: [],
modal:true,
buttons:[
Noty.button('Да', 'btn-yes', function () {
defer.resolve(true);
n.close();
}),
Noty.button('Нет', 'btn-no', function () {
defer.resolve(false);
n.close();
}),
],
}).show();
}
Суть та же, только ничего не перевыполняется два раза. Если потребуется заменить бибилиотеку, сделать это проще некуда. Все что требуется — добавить async/await к обработчикам кликов. Ну и Babel, если нужны IE.
Хотя, честно, я пользуюсь «чистыми» промисами — вполне устраивает.
Если я пишу код
if (confirm('Are you ready?')) {
alert('Yeah!')
}
То вижу вполне себе стандартное окно, если же мне нужно писать другой код, то зачем плагин ваш? Почему не взять тот же noty.js?
вот ссылка на мой пример, код взят из вашего репо http://embed.plnkr.co/aYjFDdH0LLGlTQK8hwTH/
var project = 'Тестируем';
if($(this).jdDialogs('confirm',1,['Are you ready?',project])) {
$(this).jdDialogs('alert',0,['Yeah!',project]);
}
Или вот так.
var project = 'Тестируем';
if($(this).jdDialogs('confirm',1,['Are you ready?',project])) return;
$(this).jdDialogs('alert',0,['Yeah!',project]);
Не похоже?
Что сложного переписать такой код
if(confirm('Are you sure?')) {
doSomething();
}
в такой?
bootbox.confirm('Are you sure?', function(result) {
if(result) {
doSomething();
}
})
(используется bootbox.js)
А еще, как работает else блок в вашем варианте?
if($(this).jdDialogs(....)) {
console.log('ok')
} else {
console.log('canceled!');
}
Сколько раз слово canceled напишется в консоль?
else блок в данном примере отработает 1 раз, т.к. при выборе кнопки «Отмена» повторный клик вообще не запускается. Изначально я разделял результат выбора «Отмена» и «транзитный вызов», но ни в одном из условий мне не понадобилось отмену обрабатывать.
Чтобы «Отмену» обработать пусть она возвращает не 0, а 2
.on('click','.jdCancel', function() {
methods.jdSetAnswer(2,$(this));
});
И придётся жертвовать стандартным синтаксисом вызова.
Например так:
switch($(this).jdDialogs('confirm',0,[...])) {
case 0: return;
case 1:
console.log('ok');
break;
case 2:
console.log('canceled!');
break;
default:
}
Или так:
var cnf = $(this).jdDialogs('confirm',0,[...]);
if(!cnf) return;
if(cnf == 1) {
console.log('ok');
} else {
console.log('canceled!');
}
Зачем вы предлагаете писать такое страшное мессиво из if-ов, вместо того чтобы сделать нормально?
Bootbox я привел лишь как пример хорошего API, можете написать свое решение, которое будет работать точно так же.
Главный принцип написания понятного кода — явное всегда лучше неявного. Вот код здорового человека
function handleDeleteClick() {
console.log('Before deleting record');
showConfirmModal('Delete record?').then(function () {
sendDeleteRequest();
}, function() {
console.log('Delete canceled')
});
}
а это код курильщика, в который стреляет в ногу в неожиданных местах
function handleDeleteClick() {
console.log('Before deleting record');
var result = $(this).jdDialogs('confirm',0,[...]);
if(result) {
sendDeleteRequest();
}
}
А теперь представьте, что вместо console.log там будут вызовы какой-то бизнес логики (сброс каких-нибудь состояний в UI) и я желаю вам счастливой отладки этого кода.
Ужас-ужас! Ну почему не сделать проще:
...dialog(msg, {
'Ok': function(){...},
'И еще кнопка': function(){...},
'И еще': function(){...},
'и еще!': function(){...}
},
function() // А вот отмену лучше сделать отдельно и всегда добавлять кнопку
// + эту функцию можно повесить на другие контролы,
// например на закрытие окна или клик на placeholder диалога...
{
...
});
Насколько я понимаю вы абсолютно не воспринимаете, что вам пытаются объяснить практически все комментирующие тут люди и подозреваю, что у вас впереди еще много открытий типа промисов, async, замыканий.
Вы привели отличный пример решения, которое у меня бы вызвало только один вопрос — вопрос о целесообразности работы в команде автора подобного решения. Уж извините за резкую оценку, но по-другому видимо мысль свою я донести до вас не смогу.
Имеющиеся разработки мне не подошли, т.к. хотелось по максимум сохранить синтаксис вызова…
if(confirm('') ) {...}
Выбранное решение сильно модифицирует код:
- Требует DOM элемент
- Самый ужас-ужас — многократное выполнение скрипта до confirm
Логичней, проще и правильнее перевести код на callback:
confirm = function(msg, onok, oncancel)
{
if (!ok && !oncancel) throw new Error('Пропустили что-то');
...тут использование либо готового решения, либо свое решение с вызовом onok|oncancel...
};
// Изменения в коде:
// if(confirm('') ) {...} заменяется на
confirm('', function(){...});
// if(confirm('') ) {...} else {...} заменяется на
confirm('', function(){...}, function(){...});
Естественно, что код после if(confirm('') ) тоже нужно внести в функцию onok|oncancel или добавить еще одну:
confirm = function(msg, onok, oncancel, always)
{
if (!ok && !oncancel) throw new Error('Пропустили что-то');
...тут использование либо готового решения, либо свое решение с вызовом onok|oncancel
...и последующем вызовом always
};
// if(confirm('') ) {...code on ok...} ...code after confirm... заменяется на
confirm('', function(){...code on ok...}, null, function(){...code after confirm...});
Плагин jQuery — jdDialog. Принцип «транзитных вызовов»