Ruby on Rails unobtrusive scripting adapter that enables modern JavaScript behaviors through HTML5 data attributes
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Custom event system and delegation utilities for managing user interactions and library events throughout Rails UJS.
Creates and dispatches custom events with data, providing a way to communicate between Rails UJS and application code.
/**
* Dispatch custom event on target element
* @param obj - EventTarget to dispatch event on
* @param name - Event name to dispatch
* @param data - Optional data to include in event.detail
* @returns True if event was not cancelled (defaultPrevented is false)
*/
function fire(obj: EventTarget, name: string, data?: any): boolean;Usage Examples:
const form = document.querySelector("form");
// Fire simple event
const shouldContinue = Rails.fire(form, "custom:before-submit");
if (!shouldContinue) {
console.log("Event was cancelled");
return;
}
// Fire event with data
Rails.fire(document, "rails:navigation", {
url: "/posts/1",
method: "GET"
});
// Listen for Rails UJS events
document.addEventListener("ajax:success", function(event) {
console.log("AJAX success:", event.detail);
});
// Cancel events by preventing default
document.addEventListener("confirm", function(event) {
if (!userIsAdmin) {
event.preventDefault(); // Cancels the action
}
});Efficient event delegation system that handles events for dynamically created elements.
/**
* Set up delegated event listener on container element
* @param element - Container element to listen on (usually document)
* @param selector - CSS selector for target elements
* @param eventType - Event type to listen for (click, submit, etc.)
* @param handler - Handler function to call when event matches
*/
function delegate(element: Element, selector: string, eventType: string, handler: Function): void;Usage Examples:
// Delegate click events for all remote links
Rails.delegate(document, "a[data-remote]", "click", function(event) {
console.log("Remote link clicked:", this.href);
// 'this' refers to the clicked link
});
// Delegate form submissions
Rails.delegate(document, "form[data-remote]", "submit", function(event) {
console.log("Remote form submitted:", this.action);
});
// Custom delegation for application logic
Rails.delegate(document, ".toggle-button", "click", function(event) {
this.classList.toggle("active");
});
// Delegation works with complex selectors
Rails.delegate(document, "button[data-confirm]:not([disabled])", "click", confirmHandler);Comprehensive event stopping utility that prevents all forms of event propagation.
/**
* Stop event propagation, prevent default, and fire stopping event
* @param event - Event to stop completely
*/
function stopEverything(event: Event): void;Usage Examples:
// Completely stop an event
document.addEventListener("click", function(event) {
if (event.target.disabled) {
Rails.stopEverything(event);
return;
}
});
// Used internally by Rails UJS
function handleDisabledElement(event) {
const element = this;
if (element.disabled) {
Rails.stopEverything(event); // Prevents any further processing
}
}
// Fires 'ujs:everythingStopped' event for debugging
document.addEventListener("ujs:everythingStopped", function(event) {
console.log("Event was completely stopped on:", event.target);
});Rails UJS fires numerous custom events during its operation:
// Before showing confirmation dialog
document.addEventListener("confirm", function(event) {
// event.target is the element being confirmed
// Return false or preventDefault() to skip confirmation
});
// After confirmation dialog is handled
document.addEventListener("confirm:complete", function(event) {
const [answer] = event.detail; // true if user confirmed, false if cancelled
console.log("User response:", answer);
});
// Custom confirmation handling
document.addEventListener("confirm", function(event) {
event.preventDefault();
customConfirmDialog(event.target.dataset.confirm)
.then(confirmed => {
if (confirmed) {
Rails.fire(event.target, "confirm:complete", [true]);
// Continue with original action
}
});
});// Before AJAX request starts
document.addEventListener("ajax:before", function(event) {
console.log("About to make AJAX request");
// Return false to cancel request
});
// Before XHR is sent (after beforeSend callback)
document.addEventListener("ajax:beforeSend", function(event) {
const [xhr, options] = event.detail;
console.log("Sending request to:", options.url);
});
// When XHR is actually sent
document.addEventListener("ajax:send", function(event) {
const [xhr] = event.detail;
console.log("Request sent, readyState:", xhr.readyState);
});
// When AJAX request is stopped/cancelled
document.addEventListener("ajax:stopped", function(event) {
console.log("AJAX request was stopped");
});
// On successful AJAX response (2xx status)
document.addEventListener("ajax:success", function(event) {
const [data, statusText, xhr] = event.detail;
console.log("AJAX success:", data);
});
// On AJAX error response (non-2xx status)
document.addEventListener("ajax:error", function(event) {
const [response, statusText, xhr] = event.detail;
console.error("AJAX error:", xhr.status, statusText);
});
// When AJAX request completes (success or error)
document.addEventListener("ajax:complete", function(event) {
const [xhr, statusText] = event.detail;
console.log("AJAX complete:", xhr.status);
});// Check if Rails UJS should attach bindings
document.addEventListener("rails:attachBindings", function(event) {
// Return false to prevent Rails UJS from starting
console.log("Rails UJS is initializing");
});Rails UJS uses a sophisticated delegation system:
// Example of how Rails UJS sets up delegation internally
Rails.delegate(document, "a[data-method]", "click", Rails.handleMethod);
Rails.delegate(document, "form[data-remote]", "submit", Rails.handleRemote);
Rails.delegate(document, "[data-confirm]", "click", Rails.handleConfirm);
// The delegation system:
// 1. Listens on document for efficiency
// 2. Checks event.target against selector
// 3. Bubbles up DOM tree to find matches
// 4. Calls handler with matched element as 'this'Rails UJS includes a CustomEvent polyfill for older browsers:
// Creates CustomEvent constructor if not available
// Ensures consistent behavior across all browsers
// Handles preventDefault() properly on polyfilled eventsIn delegated event handlers, this refers to the matched element:
Rails.delegate(document, "a[data-remote]", "click", function(event) {
// 'this' is the clicked <a> element that matches "a[data-remote]"
// event.target might be a child element (like <span> inside the <a>)
console.log("Clicked link:", this.href);
console.log("Actual target:", event.target.tagName);
});Install with Tessl CLI
npx tessl i tessl/npm-rails--ujs