在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对话框(例如the jQuery UI Dialog),允许用户确认或取消。
我对JavaScript的了解不足以实现这一目标。我目前的方法是简单地重写$('body')。delegate()函数来实例化灯箱。但是,我认为有一种比这更有效的方法。
答案 0 :(得分:15)
正如其他人所提到的,你不能使用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
,从而有效地取消点击事件。但是,您的自定义函数可以调用回调来实际跟随链接/提交表单。
答案 1 :(得分:13)
我刚刚在Rails jquery-ujs中添加了一个外部API,以实现这种自定义。您现在可以通过插入(并重写1行)$.rails.allowAction
函数来使rails.js使用自定义确认对话框。
请参阅我的文章Rails jQuery UJS: Now Interactive,获取有关示例的完整说明。
编辑:从this commit开始,我将confirm
对话框函数移动到$.rails
对象,以便现在可以更轻松地修改或交换它。 E.g。
$.rails.confirm = function(message) { return myConfirmDialog(message); };
答案 2 :(得分:1)
我喜欢@MarcSchütz关于覆盖$.rails.allowAction
我在网上找到的大部分内容的答案 - 但我不是在allowAction
覆盖功能的忠实粉丝,因为它在整个过程中都被使用了jquery-ujs代码库(如果有副作用怎么办?或者如果该方法的源在未来的更新中发生变化?)。
到目前为止,最好的做法是让$.rails.confirm
返回承诺......但是it doesn't look like that's going to happen anytime soon :(
所以......我推出了自己的方法,我觉得值得一提,因为它比上面提到的方法重量更轻。它没有劫持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
返回假值时暂停。所以流程是:
data-confirm
属性的链接或按钮。链接或按钮上没有data-confirmed
,因此我们会进入第一个if块,触发我们的自定义模式并返回false,从而停止在ujs单击处理程序中继续操作。 data('confirmed', true)
在元素上存储状态,并重新触发先前触发的相同事件(click.rails
)。 confirm event
会落入else
区块(因为data('confirmed')
是真的)并返回true,导致allowAction
块评估为true。我确信我甚至错过了其他可能使这更简单的方法,但我认为这是一种非常灵活的方法,可以在不破坏核心jquery-ujs
功能的情况下获得自定义确认模式。
(另外,因为我们正在使用.on()
,这将在加载时或将来绑定到页面上的任何data-confirm
元素,类似于.delegate()
的工作方式,以防万一你在想。)
答案 3 :(得分:0)
我不明白为什么当JavaScript confirm()函数仍能正常工作时你需要使用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();
})
如果您想稍微自定义对话框,请查看this example。
修改强>
现在我想到了,这对于自定义表单构建器来说是一个很好的机会。您可以覆盖一个Rails链接标记,以输出类似于上面列出的内容的html,只要存在某个属性,即:dialog => true
。当然,那将是Railsy这样做的方式。您也可以在标记中添加其他选项,例如对话框标题等。
修改强>
更好的是,而不是:dialog => true
,而不是像往常一样使用:confirm => "my confirm message"
,但是在覆盖link_to时,您将使用:confirm
选项来创建jQuery的对话框html需要,删除该选项,然后调用super
。
答案 4 :(得分:0)
这就是我开始工作的方式。请提出任何更正/改进建议
#在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中的任何位置
# <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>
答案 5 :(得分:0)
这就是我解决此问题的方法。 我尝试了很多不同的方法,但是只有一种方法有效。
在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>
我希望它将对某人有所帮助。