Steve
Steve

Reputation: 2666

Rails 5.1: How to override confirmation dialog with bootstrap using rails-ujs

Prior to Rails 5.1 I was able to use the following to customize the confirmation dialog using bootstrap styling:

$ ->
  $.rails.allowAction = (link) ->
    return true unless link.attr('data-confirm')
    $.rails.showConfirmDialog(link) 
    false 

  $.rails.confirmed = (link) ->
    link.removeAttr('data-confirm')
    link.trigger('click.rails')

  $.rails.showConfirmDialog = (link) ->
    message = link.attr 'data-confirm'
    html = """
           <div class="modal" id='confirmationDialog'>
             <div class="modal-dialog">
               <div class='modal-content'>
                 <div class='modal-header'>
                   <a class='close' data-dismiss='modal'>×</a>
                   <h3>#{message}</h3>
                 </div>
                 <div class='modal-body'>
                   <p>#{link.data('body')}</p>
                 </div>
                 <div class='modal-footer'>
                   <a data-dismiss='modal' class='btn btn-default'>#{link.data('cancel')}</a>
                   <a data-dismiss='modal' class='btn btn-danger confirm'>#{link.data('ok')}</a>
                 </div>
               </div>
             </div>
           </div>
           """
    $(html).modal()
    $('#confirmationDialog .confirm').on 'click', -> $.rails.confirmed(link)

The code stopped working with the change to rails_ujs? I've seen some articles on customizing it for SweetAlert2 but not bootstrap or other custom options.

Thanks.

Upvotes: 1

Views: 2879

Answers (4)

Martin Gerez
Martin Gerez

Reputation: 91

Following Brett Green's answer, I tweaked it using Sweet Alert:

custom_confirm_dialog.js

import Rails from '@rails/ujs';
import Swal from 'sweetalert2';

Rails.confirm = (message, element) => {
  console.log('message:', message)
  Swal.fire({
    titleText: '...',
    text: '...,
    showCancelButton: true,
    cancelButtonText: '...',
    confirmButtonText: '...',
    icon: 'warning'
  }).then(result => {
    if(result.isConfirmed) {
      const old = Rails.confirm;
      Rails.confirm = () => true;
      element.click();
      Rails.confirm = old;
    }
  }).catch(error => {
    console.log(error);
  });

  return false;
}

application.js

...
import Rails from '@rails/ujs';
Rails.start();
...
import '../src/javascripts/custom_confirm_dialog';

Working fine :)

Upvotes: 0

Brett Green
Brett Green

Reputation: 3755

For Rails 6, here's an example using bootstrap 4 dialogs:

Add modal dialog HTML to your base layout:

<div class="modal fade" id="confirmation-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog modal-dialog-centered modal-sm" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <span id="modal-content"></span>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal"><i class="fa fa-times-circle"></i> Cancel</button>
        <button type="button" class="btn btn-sm btn-primary" id='ok-button'><i class="fa fa-check"></i> Continue</button>
      </div>
    </div>
  </div>
</div>

Add javascript to override Rails.confirm and add to your global webpack:

import Rails from "@rails/ujs";

// Overrides default rails confirmation with bootstrap 4 confirm dialog
Rails.confirm = function(message, element) {
  let $element = $(element)
  let $dialog = $('#confirmation-modal')
  let $content = $dialog.find('#modal-content')
  let $ok = $dialog.find('#ok-button')
  $content.text(message)
  $ok.click(function(event) {
      event.preventDefault()
      $dialog.modal("hide")
      let old = Rails.confirm
      Rails.confirm = function() { return true }
      $element.get(0).click()
      Rails.confirm = old
    })
  $dialog.modal("show")
  return false;
}

'#modal-content' span is replaced with message text when the link/button requiring confirmation is clicked, and then the dialog is shown.

$element is the original element which gets 'clicked' if the user clicks the OK button within the dialog. This means that however complicated your rails link/button is (using posts/gets/params, etc), this simply lets that work by physically clicking it.

Upvotes: 3

Jean-Michel Gigault
Jean-Michel Gigault

Reputation: 199

Note that in Rails 6 the confirm method of Rails UJS has been made public so that you can override it, as explained in this PR: https://github.com/rails/rails/pull/32404

Upvotes: 2

Student
Student

Reputation: 13

Got following working in Rails 5.2. First using console verify presence of 'Rails' and 'BootstrapDialog' object, then put the following in a file similar to ~/app/javascripts/prj.js:

"use strict"
$(document).ready(function(){ 

  var handleConfirm = function(element) {
    if (!allowAction(this)) {
      Rails.stopEverything(element)
    }
  }

  var allowAction = function(element) {
    if (element.getAttribute('data-confirm') === null) {
      return true
    }

    showConfirmDialog(element);
    return false
  }

  var confirmed = function(element, result) {
    if (result.value) {
      // User clicked confirm button
      element.removeAttribute('data-confirm')
      element.click()
    }
  }

  var showConfirmDialog = function(link) {
    BootstrapDialog.show({
    type: BootstrapDialog.TYPE_DANGER,
    title: 'Are you sure?',
    closable: false,
    message: $(link).attr('data-confirm'),
    buttons: [
      { 
        label: 'Cancel',
        action: function(dialogRef){
          dialogRef.close();
        }
      },
      {
        label: 'Yes',
        cssClass: 'btn-danger',
        action: function(dialogRef) {
          confirmed(link);
        }
      }
    ]
  });

  $("a[data-confirm]").on('click',handleConfirm);
});

Upvotes: 0

Related Questions