Skip to content

Instantly share code, notes, and snippets.

@existentialmutt
Last active June 10, 2020 21:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save existentialmutt/317ac2adfa22a2fd32aa659f2fa96bea to your computer and use it in GitHub Desktop.
Save existentialmutt/317ac2adfa22a2fd32aa659f2fa96bea to your computer and use it in GitHub Desktop.
Confirm Navigation: Rails partial for confirming navigation with a custom modal. Built with Bootstrap and StimulusJS
// app/javascript/controllers/confirm-navigation-controller.js
import { Controller } from "stimulus";
import Rails from "rails-ujs";
export default class extends Controller {
static targets = ["confirmationModal"];
connect() {
}
confirm(event) {
const eventTarget = event.currentTarget;
event.preventDefault();
event.stopPropagation();
const promise = new Promise((resolve, reject) => {
this.confirmationResolve = resolve;
this.confirmationReject = reject;
$(this.confirmationModalTarget).modal({
backdrop: "static",
keyboard: false
});
});
promise.then(
() => {
this._navigate(eventTarget);
},
() => {}
);
}
accept(event) {
event.preventDefault();
$(this.confirmationModalTarget).modal("hide");
this.confirmationResolve();
}
reject(event) {
event.preventDefault();
$(this.confirmationModalTarget).modal("hide");
this.confirmationReject();
}
_navigate(link) {
const method = link.dataset.method || "GET";
const href = link.href || link.dataset.href;
const csrfToken = Rails.csrfToken();
const csrfParam = Rails.csrfParam();
const form = document.createElement("form");
let formContent = `<input name='_method' value='${method}' type='hidden' />`;
if (csrfParam != null && csrfToken != null && !Rails.isCrossDomain(href)) {
formContent += `<input name='${csrfParam}' value='${csrfToken}' type='hidden' />`;
}
// Must trigger submit by click on a button, else "submit" event handler won't work!
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/submit
formContent += '<input type="submit" />';
form.method = "post";
form.action = href;
if (link.target) {
form.target = link.target;
}
form.innerHTML = formContent;
form.style.display = "none";
document.body.appendChild(form);
form.querySelector('[type="submit"]').click();
}
}
-# app/views/application/_confirm_navigation.haml
- wrapper_tag ||= "div"
= content_tag wrapper_tag, data: {controller: "confirm-navigation"}, class: local_assigns[:wrapper_class] do
= slots.content_for :trigger
.modal.fade{"aria-hidden" => "true", :role => "dialog", :tabindex => "-1", data: {controller: "confirmation-modal", target: "confirm-navigation.confirmationModal"}}
.modal-dialog{:role => "document"}
.modal-content
= slots.content_for :modal_content
= render_with_slots "application/confirm_navigation" do |slots|
- slots.content_for :trigger do
%a.btn.btn-outline-danger{href: reboot_universe_path, data: {action: "confirm-navigation#confirm", method: "POST"}}
%i.fas.fa-trash.mr-1
Reboot Universe
- slots.content_for :modal_content do
.modal-body
Are you sure you want to reboot the universe and restart from the big bang? This operation cannot be undone.
.modal-footer
%button.btn.btn-outline-primary{:type => "button", data: {action: "confirm-navigation#reject"}} Cancel
%button.btn.btn-danger{:type => "button", data: {action: "confirm-navigation#accept"}}
Reboot Universe
# app/helpers/render_with_slots_helper.rb
module RenderWithSlotsHelper
def render_with_slots(partial_path, locals = {}, &block)
collector = SlotCollector.new(self)
yield(collector)
render partial_path, locals.merge(slots: collector)
end
class SlotCollector
def initialize(view_context)
@slots = {}
@view_context = view_context
end
def content_for(slot_name, &block)
if block
@slots[slot_name] = block
else
@view_context.capture_haml(&@slots[slot_name])
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment