or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ajax-remote.mdcsrf-protection.mddom-utilities.mdelement-state.mdevent-system.mdfeature-handlers.mdform-handling.mdindex.md

event-system.mddocs/

0

# Event System

1

2

Custom event system and delegation utilities for managing user interactions and library events throughout Rails UJS.

3

4

## Capabilities

5

6

### Custom Event Firing

7

8

Creates and dispatches custom events with data, providing a way to communicate between Rails UJS and application code.

9

10

```javascript { .api }

11

/**

12

* Dispatch custom event on target element

13

* @param obj - EventTarget to dispatch event on

14

* @param name - Event name to dispatch

15

* @param data - Optional data to include in event.detail

16

* @returns True if event was not cancelled (defaultPrevented is false)

17

*/

18

function fire(obj: EventTarget, name: string, data?: any): boolean;

19

```

20

21

**Usage Examples:**

22

23

```javascript

24

const form = document.querySelector("form");

25

26

// Fire simple event

27

const shouldContinue = Rails.fire(form, "custom:before-submit");

28

if (!shouldContinue) {

29

console.log("Event was cancelled");

30

return;

31

}

32

33

// Fire event with data

34

Rails.fire(document, "rails:navigation", {

35

url: "/posts/1",

36

method: "GET"

37

});

38

39

// Listen for Rails UJS events

40

document.addEventListener("ajax:success", function(event) {

41

console.log("AJAX success:", event.detail);

42

});

43

44

// Cancel events by preventing default

45

document.addEventListener("confirm", function(event) {

46

if (!userIsAdmin) {

47

event.preventDefault(); // Cancels the action

48

}

49

});

50

```

51

52

### Event Delegation

53

54

Efficient event delegation system that handles events for dynamically created elements.

55

56

```javascript { .api }

57

/**

58

* Set up delegated event listener on container element

59

* @param element - Container element to listen on (usually document)

60

* @param selector - CSS selector for target elements

61

* @param eventType - Event type to listen for (click, submit, etc.)

62

* @param handler - Handler function to call when event matches

63

*/

64

function delegate(element: Element, selector: string, eventType: string, handler: Function): void;

65

```

66

67

**Usage Examples:**

68

69

```javascript

70

// Delegate click events for all remote links

71

Rails.delegate(document, "a[data-remote]", "click", function(event) {

72

console.log("Remote link clicked:", this.href);

73

// 'this' refers to the clicked link

74

});

75

76

// Delegate form submissions

77

Rails.delegate(document, "form[data-remote]", "submit", function(event) {

78

console.log("Remote form submitted:", this.action);

79

});

80

81

// Custom delegation for application logic

82

Rails.delegate(document, ".toggle-button", "click", function(event) {

83

this.classList.toggle("active");

84

});

85

86

// Delegation works with complex selectors

87

Rails.delegate(document, "button[data-confirm]:not([disabled])", "click", confirmHandler);

88

```

89

90

### Event Stopping

91

92

Comprehensive event stopping utility that prevents all forms of event propagation.

93

94

```javascript { .api }

95

/**

96

* Stop event propagation, prevent default, and fire stopping event

97

* @param event - Event to stop completely

98

*/

99

function stopEverything(event: Event): void;

100

```

101

102

**Usage Examples:**

103

104

```javascript

105

// Completely stop an event

106

document.addEventListener("click", function(event) {

107

if (event.target.disabled) {

108

Rails.stopEverything(event);

109

return;

110

}

111

});

112

113

// Used internally by Rails UJS

114

function handleDisabledElement(event) {

115

const element = this;

116

if (element.disabled) {

117

Rails.stopEverything(event); // Prevents any further processing

118

}

119

}

120

121

// Fires 'ujs:everythingStopped' event for debugging

122

document.addEventListener("ujs:everythingStopped", function(event) {

123

console.log("Event was completely stopped on:", event.target);

124

});

125

```

126

127

## Rails UJS Events

128

129

Rails UJS fires numerous custom events during its operation:

130

131

### Confirmation Events

132

133

```javascript

134

// Before showing confirmation dialog

135

document.addEventListener("confirm", function(event) {

136

// event.target is the element being confirmed

137

// Return false or preventDefault() to skip confirmation

138

});

139

140

// After confirmation dialog is handled

141

document.addEventListener("confirm:complete", function(event) {

142

const [answer] = event.detail; // true if user confirmed, false if cancelled

143

console.log("User response:", answer);

144

});

145

146

// Custom confirmation handling

147

document.addEventListener("confirm", function(event) {

148

event.preventDefault();

149

customConfirmDialog(event.target.dataset.confirm)

150

.then(confirmed => {

151

if (confirmed) {

152

Rails.fire(event.target, "confirm:complete", [true]);

153

// Continue with original action

154

}

155

});

156

});

157

```

158

159

### AJAX Events

160

161

```javascript

162

// Before AJAX request starts

163

document.addEventListener("ajax:before", function(event) {

164

console.log("About to make AJAX request");

165

// Return false to cancel request

166

});

167

168

// Before XHR is sent (after beforeSend callback)

169

document.addEventListener("ajax:beforeSend", function(event) {

170

const [xhr, options] = event.detail;

171

console.log("Sending request to:", options.url);

172

});

173

174

// When XHR is actually sent

175

document.addEventListener("ajax:send", function(event) {

176

const [xhr] = event.detail;

177

console.log("Request sent, readyState:", xhr.readyState);

178

});

179

180

// When AJAX request is stopped/cancelled

181

document.addEventListener("ajax:stopped", function(event) {

182

console.log("AJAX request was stopped");

183

});

184

185

// On successful AJAX response (2xx status)

186

document.addEventListener("ajax:success", function(event) {

187

const [data, statusText, xhr] = event.detail;

188

console.log("AJAX success:", data);

189

});

190

191

// On AJAX error response (non-2xx status)

192

document.addEventListener("ajax:error", function(event) {

193

const [response, statusText, xhr] = event.detail;

194

console.error("AJAX error:", xhr.status, statusText);

195

});

196

197

// When AJAX request completes (success or error)

198

document.addEventListener("ajax:complete", function(event) {

199

const [xhr, statusText] = event.detail;

200

console.log("AJAX complete:", xhr.status);

201

});

202

```

203

204

### Initialization Events

205

206

```javascript

207

// Check if Rails UJS should attach bindings

208

document.addEventListener("rails:attachBindings", function(event) {

209

// Return false to prevent Rails UJS from starting

210

console.log("Rails UJS is initializing");

211

});

212

```

213

214

## Event Delegation Implementation

215

216

Rails UJS uses a sophisticated delegation system:

217

218

```javascript

219

// Example of how Rails UJS sets up delegation internally

220

Rails.delegate(document, "a[data-method]", "click", Rails.handleMethod);

221

Rails.delegate(document, "form[data-remote]", "submit", Rails.handleRemote);

222

Rails.delegate(document, "[data-confirm]", "click", Rails.handleConfirm);

223

224

// The delegation system:

225

// 1. Listens on document for efficiency

226

// 2. Checks event.target against selector

227

// 3. Bubbles up DOM tree to find matches

228

// 4. Calls handler with matched element as 'this'

229

```

230

231

## CustomEvent Polyfill

232

233

Rails UJS includes a CustomEvent polyfill for older browsers:

234

235

```javascript

236

// Creates CustomEvent constructor if not available

237

// Ensures consistent behavior across all browsers

238

// Handles preventDefault() properly on polyfilled events

239

```

240

241

## Performance Benefits

242

243

- **Single listener per event type**: Uses delegation instead of individual listeners

244

- **Dynamic content support**: Automatically handles elements added after page load

245

- **Memory efficient**: No need to add/remove listeners when elements change

246

- **Event bubbling**: Leverages native browser event bubbling for efficiency

247

248

## Event Handler Context

249

250

In delegated event handlers, `this` refers to the matched element:

251

252

```javascript

253

Rails.delegate(document, "a[data-remote]", "click", function(event) {

254

// 'this' is the clicked <a> element that matches "a[data-remote]"

255

// event.target might be a child element (like <span> inside the <a>)

256

console.log("Clicked link:", this.href);

257

console.log("Actual target:", event.target.tagName);

258

});

259

```