Search
Write a publication
Pull to refresh

Comments 22

Эпоха плагинов для jQ прошла уже… ну вобщем давно :)

Плюс, вы никак не сделаете замену confirm() на кастомных окошках. Вот вообще никак, т.к. всплывающие html-окна не будут блокировать исполнение кода. То, что реализовано в статье — обычный callback.

Максимально приближенный вариант будет что-то вроде:
async function() { // Здесь выполняется наш код. Да, в async
    if (await jdDialog(...)) { // Ваша функция должна вернуть true
        ...
    }
}

Но такое поведение будет доступно только если вы реализуете промисы и только в async-функциях, само-собой.

P.S. Советую взглянуть на библиотеку noty js
Это то, что вам нужно, только с бОльшими возможностями.
Спасибо за совет! Понятно, что есть новые технологии. Здесь решение несколько другой задачи — чуть-чуть подправить действующий проект согласно заданию. А код тем не менее если можно так сказать всё-таки «блокируется». Выводом в return. Для возобновления кода по выбору в диалоговом окне запускается заново, но то же самое диалоговое окно не генерируется, а возвращается «транзитом» выбор пользователя. В этом суть принципа.
Смутил синтаксис if (...), посмотрел ваши исходники.
Не делайте так :) Если кто-то будет потом поддерживать этот код, он повесится. Дважды, как и код.

Поскольку заблокировать выполнение в JS не получится, вы решили «перекликивать» элемент. Это ужасное решение.

1. Что если на клике висят и другие обработчики событий?
2. Что если до if (jdDialog) есть каокй-то код?

В обоих случаях код будет выполнен дважды.

А если нужно вызвать диалог без клика? Ну и т.д.
Совершенно верно, «перекликивать». Это ни в коем случае не универсальное решение на все случаи жизни. Для простых случаев, а таких задач думаю большинство, if confirm и alert вполне себе работает.
Для более сложных алгоритмов естественно уже не подходит. Хотя и тут можно найти решение. Например по другому селектору инициировать клик. Здесь сознательно я иду на повторное выполнение кода, поэтому на этот факт придётся оглядываться.
Ещё раз повторяю, найденное решение — для определённой ниши задач.
Просто вы себе кучу проблем наживете в будущем. Дело конечно ваше, но почему бы не переделать, например так?

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.

Хотя, честно, я пользуюсь «чистыми» промисами — вполне устраивает.
Noty.js не подходит. Вызов отличается от if(confirm()) {}. Данный плагин разработан именно для того, чтобы сделать замену стандартному confirm.
Я может чего не понимаю, но собственно где замена то стандартным диалоговым окнам у вас получилась?
Если я пишу код
    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]);


Не похоже?
Noty.js не подошёл мне по синтаксису вызова (это указано в статье в постановке задачи), к тому же он более тяжеловесный. Речь в статье не о «добавил в свой код готовое решение и забыл», а об описании принципа. Плагин — это просто реализация принципа. Функционала данного плагина для замены диалоговых окон в моём проекте оказалось достаточно. Кстати если в confirm нужно обрабатывать cancel, достаточно разделить ответ 0 на Отмену и «транзитный вызов».

Что сложного переписать такой код


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 напишется в консоль?

Добрый день! Да, спасибо! Если бы в своё время его нашёл, скорее всего он и был бы использован. Синтаксис вызова под задачу вполне подходящий. Но тогда придётся ставить в проект Bootstrap. Кроме того в предлагаемой мной реализации имеется полная свобода в оформлении диалогового окна (хоть полностью круглым его сделать), можно добавлять неограниченное кол-во кнопок и прочих элементов управления + шапка. Трёхкнопочное окно кстати в своём проекте использую.

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, можете написать свое решение, которое будет работать точно так же.

Да, к сожалению проблема лишнего кода имеет место — id диалогового окна, привязка к элементу. При увеличении количества кнопок лишний код. Тем не менее предложенный принцип работает. Предполагаю, что при развитии идеи вполне можно найти решения большинства шероховатостей. Ещё раз говорю, что принцип родился в процессе реализации конкретной задачи и может быть его можно применить не только для диалоговых окон. А Bootbox кто же спорит — безусловно отличный проект.

Главный принцип написания понятного кода — явное всегда лучше неявного. Вот код здорового человека


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('') ) {...}

Выбранное решение сильно модифицирует код:


  1. Требует DOM элемент
  2. Самый ужас-ужас — многократное выполнение скрипта до 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...});
Большое спасибо всем комментировавшим статью! Действительно много более надёжных вариантов решения.
Sign up to leave a comment.

Articles