jQuery UI Dialog вместо alert () для атрибута подтверждения данных Rails 3 - PullRequest
13 голосов
/ 12 декабря 2010

В Rails 3 передача параметра: verify в link_to заполняет атрибут data-Подтверждение ссылки.Это вызовет предупреждение JS () при нажатии на ссылку.

Я использую адаптер jQuery UJS для rails (https://github.com/rails/jquery-ujs). Соответствующий код из rails.js:

$('body').delegate('a[data-confirm], button[data-confirm], input[data-confirm]', 'click.rails', function () {
    var el = $(this);
    if (el.triggerAndReturn('confirm')) {
        if (!confirm(el.attr('data-confirm'))) {
            return false;
        }
    }
});

и

triggerAndReturn: function (name, data) {
        var event = new $.Event(name);
        this.trigger(event, data);

        return event.result !== false;
    }

Iхотел бы знать, как это можно изменить, чтобы вместо этого получить диалоговое окно jQuery (например, диалоговое окно jQuery UI ), позволяющее пользователю подтвердить или отменить.

Моих знаний о JavaScript недостаточночтобы достичь этого элегантно. Мой нынешний подход состоит в том, чтобы просто переписать функцию $ ('body'). делегат (), чтобы вместо этого создать экземпляр лайтбокса. Однако я думаю, что есть более эффективный подход, чем этот.

Ответы [ 6 ]

15 голосов
/ 24 июня 2011

Как уже упоминалось, вы не можете использовать диалоговое окно jQuery, так как $.rails.confirm нужно блокировать, пока он не ответит пользователю.

Однако вы можете перезаписать $.rails.allowAction в файле application.js следующим образом:

$.rails.allowAction = function(element) {
        var message = element.data('confirm'),
        answer = false, callback;
        if (!message) { return true; }

        if ($.rails.fire(element, 'confirm')) {
                myCustomConfirmBox(message, function() {
                        callback = $.rails.fire(element,
                                'confirm:complete', [answer]);
                        if(callback) {
                                var oldAllowAction = $.rails.allowAction;
                                $.rails.allowAction = function() { return true; };
                                element.trigger('click');
                                $.rails.allowAction = oldAllowAction;
                        }
                });
        }
        return false;
}

function myCustomConfirmBox(message, callback) {
        // implement your own confirm box here
        // call callback() if the user says yes
}

Это работает, возвращая false немедленно, таким образом эффективно отменяя событие щелчка. Однако ваша пользовательская функция может затем вызвать обратный вызов, чтобы фактически перейти по ссылке / отправить форму.

13 голосов
/ 26 апреля 2011

Я просто добавил внешний API к Rails jquery-ujs именно для этого вида настройки.Теперь вы можете заставить rails.js использовать пользовательский диалог подтверждения, подключив (и переписав 1 строку) функцию $.rails.allowAction.

См. Мою статью, Rails jQuery UJS: Now Interactive , для полного объяснения с примерами.

РЕДАКТИРОВАТЬ: Начиная с этого коммита , я переместил функцию диалога confirm в объект $.rails, чтобы его можно было изменитьили поменяться еще проще сейчас.Например,

$.rails.confirm = function(message) { return myConfirmDialog(message); };
1 голос
/ 29 июля 2015

Мне понравился ответ @Marc Schütz о переопределении $.rails.allowAction большинства всего, что я нашел в Интернете - но я не большой поклонник переопределения функциональности в allowAction, так как она используется повсеместно в кодовой базе jquery-ujs(что если есть побочные эффекты? Или если источник для этого метода изменится в будущем обновлении?).

На сегодняшний день лучшим подходом было бы заставить $.rails.confirm вернуть обещание ... Но не похоже, что это произойдет в ближайшее время : (

Итак ... Я применил свой собственный метод, который, я думаю, стоит упомянуть, потому что он легче, чем метод, описанный выше. Он не угоняет allowAction. Вот он:

# Nuke the default confirmation dialog. Always return true 
# since we don't want it blocking our custom modal.
$.rails.confirm = (message) -> true

# Hook into any data-confirm elements and pop a custom modal
$(document).on 'confirm', '[data-confirm]', ->
  if !$(this).data('confirmed')
    myCustomModal 'Are you sure?', $(this).data('confirm'), =>
      $(this).data('confirmed', true)
      $(this).trigger('click.rails')
    false
  else
    true

# myCustomModal is a function that takes (title, message, confirmCallback)

Какэто работает? Хорошо, если вы посмотрите на source , вы заметите, что метод allowAction останавливается, если confirm event возвращает ложное значение. Таким образом, поток:

  1. Пользователь нажимает на ссылку или кнопку с атрибутом data-confirm. На ссылке или кнопке отсутствует data-confirmed, поэтому мы попадаем в первый блок if, запускаем наш пользовательский модальный режим и возвращаем false, тем самым останавливая действие изпродолжение в обработчике кликов ujs.
  2. Пользователь подтверждает в пользовательском модале, и вызывается обратный вызов. Мы сохраняем состояние элемента через data('confirmed', true) и повторно инициируем то же событие, которое было инициировано ранее (click.rails).
  3. На этот раз confirm event попадет в блок else (поскольку data('confirmed') является правдивым) и вернет true, в результате чего блок allowAction оценивается как true.

Я уверен, что даже пропалдругие способы, которые могут сделать это еще проще, но я думаю, что это действительно гибкий подход, чтобы получить пользовательский модал подтверждения без нарушения базовой jquery-ujs функциональности.

(Кроме того, поскольку мы используем .on() thisбудет связываться с любыми data-confirm элементами на странице во время загрузки или в будущем, аналогично тому, как работает .delegate(), если вам интересно.)

0 голосов
/ 28 декабря 2018

Вот как я решил эту проблему.Я пробовал много разных способов, но работает только этот.

В rails.js

function myCustomConfirmBox(element, callback) {

    const modalConfirmDestroy = document.getElementById('modal-confirm');

    // wire up cancel
    $("#modal-confirm #cancel-delete").click(function (e) {
        e.preventDefault();
        modalConfirmDestroy.classList.remove('modal--open');
    });

    // wire up OK button.
    $("#modal-confirm #confirm-delete").click(function (e) {
        e.preventDefault();
        modalConfirmDestroy.classList.remove('modal--open');
        callback(element, true);
    });

    // show the dialog.
    modalConfirmDestroy.classList.add('modal--open');
}

В этом месте я использовал код @Mark G. с некоторыми изменениями.Потому что этот $ (this) .trigger ('click.rails') фрагмент кода не работал для меня.

$.rails.confirm = function(message) {return true};

$(document).on('confirm', '[data-confirm]', (event)=> {
    if (!$(this).data('confirmed'))
    {
        myCustomConfirmBox($(this), (element, choice)=> {
            element.data('confirmed', choice);
            let clickedElement = document.getElementById(event.target.id);
            clickedElement.click();
        });
        return false;
    }
    else
    {
        return true;
    }
});

Тогда в файле html.erb у меня есть этот код для ссылки:

<%= link_to "documents/#{document.id}", method: "delete", data: {confirm: "sure?"}, id: "document_#{document.id}" %>

и этот код для модального:

<div id="modal-confirm" class="modal modal-confirm">
  <h2 class="modal__ttl">Title</h2>
  <div class="modal__inner">
    <p>Description</p>
    <div class="modal__btns">
      <button type="button" name="cancel" id="cancel-delete" class="btn btn-primary">Cancel</button>
      <button type="button" name="confirm" id="confirm-delete" class="btn delete_button btn-secondary">Delete</button>
    </div>
  </div>
</div>

Я надеюсь,это кому-то поможет.

0 голосов
/ 17 февраля 2011

Вот как я заставил это работать. Пожалуйста, предлагайте любые исправления / улучшения

#

в rails.js

#
// Added new variable
var deleteConfirmed = false;

// Changed function to use jquery dialog instead of confirm   
$('body').delegate('a[data-confirm], button[data-confirm], input[data-confirm]', 'click.rails', function () {
        var el = $(this);
        /*
        if (el.triggerAndReturn('confirm')) {

            if (!confirm(el.attr('data-confirm'))) {
                return false;
            }

        }
        */

        if (el.triggerAndReturn('confirm')) {    

            if(deleteConfirmed) {
                deleteConfirmed = false;
                return true;
            }

            $( "#dialog-confirm" ).dialog("option", "buttons",
                    {
                        "Delete": function() {
                            $( this ).dialog( "close" );
                            deleteConfirmed = true;
                            el.trigger('click');   
                            return true;
                        },
                        Cancel: function() {
                            $( this ).dialog( "close" );
                            return false;
                        }
                    }
            );

            $( "#dialog-confirm" ).dialog("open");

            return false;

        }


    });
#

в приложении. Js

#
//Ensure confirm Dialog is pre-created
jQuery(function () {


    $( "#dialog-confirm" ).dialog({
        autoOpen: false,
        resizable: false,
        height:140,
        modal: true     
    });

});
#

в layout.html Alt вы можете поместить этот div в любом месте вашего сгенерированного HTML

#
        <div id='dialog-confirm' title='Confirm Delete'> 
          <p> 
            <span class='ui-icon-alert' style='float:left; margin:0 7px 20px 0;'> 
              This item will be permanently deleted. Are you sure?
            </span> 
          </p> 
        </div> 
0 голосов
/ 13 декабря 2010

Я не понимаю, почему вам нужно использовать диалоговое окно jQuery, когда функция подтверждения JavaScript () все еще будет работать нормально.Я хотел бы сделать что-то вроде этого:

$('a[data-confirm]').click(funciton() {
  confirm($(this).data("confirm"));
});

Если вы хотите использовать вместо этого диалог, это немного по-другому.Вы можете выбрать одно диалоговое окно по своему усмотрению или, возможно, использовать приложение с единообразным подходом, чтобы ваш rails.js или application.js могли обрабатывать любой экземпляр диалога.Например, вам нужно что-то вроде этого на вашей странице:

<a class="dialogLauncher">The link that creates your dialog</a>
<div class="dialog" title="My confirmation title" style="display:none">
  <p>My confirmation message</p>
</div>

Затем в вашем js:

$('.dialogLauncher').click(function() {
  var dialog = $(this).next('.dialog');
  dialog.dialog();
})

Если вы хотите немного больше настроить свой диалог, отметьтеout этот пример .

Edit

Теперь, когда я думаю об этом, это была бы хорошая возможность для создателя пользовательских форм.Вы можете переопределить один из ваших тегов ссылок Rails для вывода html, аналогичного тому, что указан выше, когда присутствует определенный атрибут, например :dialog => true.Конечно, это был бы Railsy способ сделать это.Вы также можете добавить в свой тег другие параметры, такие как заголовок диалогового окна и т. Д.

Редактировать

Еще лучше, вместо :dialog => true, использовать :confirm => "my confirm message"как обычно, но при переопределении link_to вы будете использовать опцию :confirm, чтобы создать html-диалог, необходимый jQuery, удалить эту опцию и затем вызвать super.

...