用于Rails 3数据确认属性的jQuery UI Dialog而不是alert()

在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()函数来实例化灯箱。 但是,我认为有一种比这更有效的方法。

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

请参阅我的文章, Rails jQuery UJS:Now Interactive ,以获得有关示例的完整说明。

编辑:在此提交时 ,我将confirm对话框函数移动到$.rails对象,以便现在可以更轻松地修改或交换它。 例如

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

正如其他人提到的那样,你不能使用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 ,从而有效地取消了click事件。 但是,您的自定义函数可以调用回调来实际跟随链接/提交表单。

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

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

如果你想使用对话框,那就有点不同了。 您可以一次性关闭所需的每个对话框,或者您可以在应用程序范围内采用统一的方法,以便rails.js或您的application.js可以处理任何对话框实例。 例如,您在页面上需要这样的内容:

 The link that creates your dialog  

然后,在你的js中:

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

如果您想稍微自定义对话框,请查看此示例 。

编辑

现在我想到了,这对于自定义表单构建器来说是一个很好的机会。 您可以覆盖其中一个Rails链接标记,以便在存在某个属性时输出类似于上面列出的内容的html,即:dialog => true 。 当然,那将是Railsy这样做的方式。 您也可以在标记中添加其他选项,例如对话框标题等。

编辑

更好的是,而不是:dialog => true ,使用:confirm => "my confirm message"就像平常一样,但是在你的link_to覆盖中,你将使用:confirm选项来创建jQuery需要的对话框html,删除该选项,然后调用super

这就是我开始工作的方式。 请提出任何更正/改进建议

在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 Alt中,您可以将此div放在生成的html中的任何位置

  

This item will be permanently deleted. Are you sure?

我喜欢@MarcSchütz关于覆盖$.rails.allowAction的答案我在网上找到的大部分内容 – 但是我不是在覆盖allowAction的function的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) 

它是如何工作的? 好吧,如果你查看源代码 ,你会注意到如果confirm event返回一个假值, allowAction方法就会停止。 所以流程是:

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

我确信我甚至错过了其他可能使这更简单的方法,但我认为这是一种非常灵活的方法来获得自定义确认模式而不破坏核心jquery-ujsfunction。

(另外,因为我们正在使用.on() ,所以在加载时或将来会绑定到页面上的任何data-confirm元素,类似于.delegate()工作方式,以防您想知道。)