jQuery UI 对话框而不是 Rails 3 数据确认属性的alert()

发布于 2024-10-07 02:02:30 字数 981 浏览 9 评论 0原文

在 Rails 3 中,将 :confirm 参数传递给 link_to 将填充链接的 data-confirm 属性。单击链接时,这将引发 JS Alert()。

我正在使用 Rails jQuery UJS 适配器 (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;
    }

想知道如何修改它以生成 jQuery 对话框(例如 jQuery UI 对话框)允许用户确认或取消。

我对 JavaScript 的了解不足以优雅地实现这一点。我当前的方法是简单地重写 $('body').delegate() 函数来实例化一个灯箱。但我认为有比这更有效的方法。

In Rails 3, passing a :confirm parameter to link_to will populate the data-confirm attribute of the link. This will induce a JS alert() when the link is clicked.

I am using the rails jQuery UJS adapter (https://github.com/rails/jquery-ujs). The relevant code from rails.js is:

$('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;
        }
    }
});

and

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

        return event.result !== false;
    }

I would like to know how this could be modified to instead yield a jQuery dialog (e.g. the jQuery UI Dialog) allowing the user to confirm or cancel.

My knowledge of JavaScript isn't sufficient to achieve this elegantly. My current approach would be to simply rewrite the $('body').delegate() function to instead instantiate a lightbox. However I imagine that there is a more effective approach than this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

别再吹冷风 2024-10-14 02:02:30

正如其他人提到的,您不能使用 jQuery 对话框,因为 $.rails.confirm 需要阻塞,直到返回用户答案。

但是,您可以在 application.js 文件中覆盖 $.rails.allowAction,如下所示:

$.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,从而有效地取消点击事件。但是,您的自定义函数随后可以调用回调来实际跟踪链接/提交表单。

As others have mentioned, you cannot use a jQuery dialog box, as $.rails.confirm needs to block until it returns the users answer.

However, you can overwrite $.rails.allowAction in your application.js file like this:

$.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
}

It works by returning false immediately, thus effectively canceling the click event. However, your custom function can then call the callback to actually follow the link/submit the form.

反目相谮 2024-10-14 02:02:30

我刚刚向 Rails jquery-ujs 添加了一个外部 API,以实现此类自定义。现在,您可以通过插入(并重写 1 行)$.rails.allowAction 函数,使rails.js 使用自定义确认对话框。

请参阅我的文章 Rails jQuery UJS:现在交互式,了解带有示例的完整解释。

编辑:从此提交开始,我移动了confirm $.rails 对象的对话框功能,以便现在可以更轻松地修改或交换它。例如

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

I just added an external API to the Rails jquery-ujs for exactly this kind of customization. You can now make rails.js use a custom confirm dialog by plugging into (and re-writing 1 line of) the $.rails.allowAction function.

See my article, Rails jQuery UJS: Now Interactive, for a full explanation with examples.

EDIT: As of this commit, I moved the confirm dialog function to the $.rails object, so that it can be modified or swapped out even more easily now. E.g.

$.rails.confirm = function(message) { return myConfirmDialog(message); };
茶花眉 2024-10-14 02:02:30

我喜欢 @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)

如何工作的? blob/master/src/rails.js#L283" rel="nofollow">源,您会注意到,如果 confirm 事件allowAction 方法会停止> 返回一个虚假值,因此流程是:

  1. 用户单击带有 data-confirm 属性的链接或按钮 链接或按钮上没有 data-confirmed 。我们陷入第一个 if 块,触发我们的自定义模式并返回 false,从而停止在 ujs 单击处理程序中继续执行
  2. 用户在自定义模式中确认的操作,并触发回调。我们通过 data('confirmed', true) 存储元素的状态,并重新触发之前触发的相同事件 (click.rails)。
  3. 这次 confirm 事件 将落入 else 块(因为 data('confirmed') 为 true)并返回 true,导致 < code>allowAction 块评估为 true。

我确信我什至错过了可能使这变得更加简单的其他方法,但我认为这是一种非常灵活的方法,可以在不破坏核心 jquery-ujs 功能的情况下获得自定义确认模式。

(此外,因为我们使用 .on() ,这将在加载时或将来绑定到页面上的任何 data-confirm 元素,类似于 < code>.delegate() 有效,以防您想知道。)

I liked the answer from @Marc Schütz about overriding $.rails.allowAction the most of anything I found online - but I'm not a big fan of overriding the functionality in allowAction since it's used all throughout the jquery-ujs codebase (what if there are side effects? Or if the source for that method changes in a future update?).

By far, the best approach would be to make $.rails.confirm return a promise... But it doesn't look like that's going to happen anytime soon :(

So... I rolled my own method which I think is worth mentioning because it's lighter weight than the method outlined above. It doesn't hijack allowAction. Here it is:

# 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)

How does it work? Well, if you look at the source, you'll notice that the allowAction method halts if the confirm event returns a falsy value. So the flow is:

  1. User clicks link or button with data-confirm attribute. There is no data-confirmed present on the link or button, so we fall into the first if block, trigger our custom modal and return false, thereby stopping the action from continuing in the ujs click handler.
  2. User confirms in the custom modal, and the callback is triggered. We store state on the element via data('confirmed', true) and re-trigger the same event that was triggered previously (click.rails).
  3. This time the confirm event will fall into the else block (since data('confirmed') is truthy) and return true, causing the allowAction block to evaluate to true.

I'm sure I'm even missing other ways that might make this even simpler, but I think this is a really flexible approach to get a custom confirm modal without breaking core jquery-ujs functionality.

(Also, because we're using .on() this will bind to any data-confirm elements on the page at load time or in the future, similarly to how .delegate() works, in case you are wondering.)

雄赳赳气昂昂 2024-10-14 02:02:30

我不明白为什么当 JavaScript 确认()函数仍然可以正常工作时您需要使用 jQuery 对话框。我会做这样的事情:

$('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();
})

如果您想进一步自定义对话框,请查看 此示例

编辑

现在我想起来,这对于自定义表单生成器来说是一个很好的机会。只要存在某个属性,您就可以覆盖 Rails 链接标记之一以输出类似于上面列出的 html,即 :dialog =>正确。当然,这就是 Railsy 的做法。您还可以在标记中添加其他选项,例如对话框标题等。

编辑

更好的是,而不是 :dialog => true,使用:confirm => “我的确认消息” 就像平常一样,但是在覆盖 link_to 时,您将使用 :confirm 选项创建 jQuery 需要的对话框 html,删除该选项,然后然后调用super

I don't understand why you need to use the jQuery dialog when the JavaScript confirm() function will still work just fine. I would do something like this:

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

If you want to use a dialog instead, it's a little different. You can one-off each dialog you want, or you can probably take a uniform approach application wide so that your rails.js or your application.js can handle any dialog instance. For example, you'd need something like this on your page:

<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>

Then, in your js:

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

If you want to customize your dialog a little more, check out this example.

Edit

Now that I think of it, this would be a good opportunity for a custom form builder. You could override one of your Rails link tags to output html similar to what's listed above whenever a certain attribute is present, i.e. :dialog => true. Surely that would be the Railsy way to do it. You could add other options into your tag as well, like the dialog title, etc.

Edit

Better yet, instead of :dialog => true, use :confirm => "my confirm message" just as you would normally, but in your override of link_to, you will use the :confirm option to create the dialog html that jQuery needs, delete that option, and then call super.

别低头,皇冠会掉 2024-10-14 02:02:30

这就是我让它发挥作用的方式。 任何更正/改进

#

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;

        }


    });

#

application.js中的

#

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


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

});

#

请建议对layout.html中的
您可以将此 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> 

This is how I got it to work. Please suggest any corrections / improvements

#

in 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;

        }


    });

#

in application.js

#

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


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

});

#

in layout.html
Alt you can place this div anywhere in your generated 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> 
软甜啾 2024-10-14 02:02:30

这就是我解决这个问题的方法。
我尝试了很多不同的方法,但只有这个有效。

在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>

我希望它会对某人有所帮助。

This is how I solved this problem.
I tried a lot of different ways, but only this one works.

In 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');
}

In this place I used code of @Mark G. with some changes. Because this $(this).trigger('click.rails') snipped of the code didn't work for me.

$.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;
    }
});

Then in the html.erb file I have this code for link:

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

and this code for modal:

<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>

I hope, it will help someone.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文