render_async 2.1.0 β 2.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.all-contributorsrc +88 -2
- data/.github/CONTRIBUTING.md +40 -0
- data/.github/FUNDING.yml +3 -0
- data/.gitignore +1 -0
- data/.gitmodules +4 -0
- data/CHANGELOG.md +71 -0
- data/README.md +405 -70
- data/app/views/render_async/_render_async.html.erb +20 -23
- data/app/views/render_async/_request_jquery.js.erb +146 -37
- data/app/views/render_async/_request_vanilla.js.erb +152 -38
- data/bin/integration-tests +7 -0
- data/lib/render_async/configuration.rb +4 -1
- data/lib/render_async/version.rb +1 -1
- data/lib/render_async/view_helper.rb +63 -23
- metadata +8 -7
data/README.md
CHANGED
|
@@ -1,31 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src='http://s2blog.wpengine.com/wp-content/uploads/assets/images/2017-06-08/speed-up-rendering-rails-pages-with-render-async.png' alt='render_async' />
|
|
3
|
+
|
|
4
|
+
<h1 align="center">π Welcome to render_async</h1>
|
|
5
|
+
|
|
6
|
+
<h3 align="center">Let's make your Rails pages fast again :racehorse:</h3>
|
|
7
|
+
|
|
8
|
+
<br />
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.paypal.me/nikolalsvk/10" target="_blank">
|
|
12
|
+
<img src="https://img.shields.io/badge/$-support-green.svg" alt="Donate" />
|
|
13
|
+
</a>
|
|
14
|
+
<a href="https://rubygems.org/gems/render_async" target="_blank">
|
|
15
|
+
<img src="https://img.shields.io/gem/dt/render_async" alt="Downloads" />
|
|
16
|
+
</a>
|
|
17
|
+
<a href="#contributors" target="_blank">
|
|
18
|
+
<img src="https://img.shields.io/github/all-contributors/renderedtext/render_async" alt="All contributors" />
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://badge.fury.io/rb/render_async" target="_blank">
|
|
21
|
+
<img src="https://badge.fury.io/rb/render_async.svg" alt="Gem Version" />
|
|
22
|
+
</a>
|
|
23
|
+
<br />
|
|
24
|
+
<a href="https://discord.gg/SPfbeRm" target="_blank">
|
|
25
|
+
<img src="https://img.shields.io/discord/738783603214909521" alt="Discord Server" />
|
|
26
|
+
</a>
|
|
27
|
+
<a href="https://semaphoreci.com/renderedtext/render_async" target="_blank">
|
|
28
|
+
<img src="https://semaphoreci.com/api/v1/renderedtext/render_async/branches/master/shields_badge.svg" alt="Build Status" />
|
|
29
|
+
</a>
|
|
30
|
+
<a href="https://codeclimate.com/github/renderedtext/render_async" target="_blank">
|
|
31
|
+
<img src="https://img.shields.io/codeclimate/maintainability/renderedtext/render_async" alt="Code Climate Maintainablity" />
|
|
32
|
+
</a>
|
|
33
|
+
<a href="https://codeclimate.com/github/renderedtext/render_async/coverage" target="_blank">
|
|
34
|
+
<img src="https://img.shields.io/codeclimate/coverage/renderedtext/render_async" alt="Test Coverage" />
|
|
35
|
+
</a>
|
|
36
|
+
<a href="https://github.com/renderedtext/render_async/blob/master/LICENSE" target="_blank">
|
|
37
|
+
<img src="https://img.shields.io/github/license/renderedtext/render_async" alt="License" />
|
|
38
|
+
</a>
|
|
39
|
+
<a href="https://www.codetriage.com/renderedtext/render_async" target="_blank">
|
|
40
|
+
<img src="https://www.codetriage.com/renderedtext/render_async/badges/users.svg" alt="Help Contribute to Open Source" />
|
|
41
|
+
</a>
|
|
42
|
+
</p>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
### `render_async` is here to make your pages show faster to users.
|
|
46
|
+
|
|
47
|
+
Pages become faster seamlessly by rendering partials to your views.
|
|
48
|
+
|
|
49
|
+
Partials render **asynchronously** and let users see your page **faster**
|
|
50
|
+
than using regular rendering.
|
|
51
|
+
|
|
52
|
+
It works with Rails and its tools out of the box.
|
|
53
|
+
|
|
54
|
+
:sparkles: A quick overview of how `render_async` does its magic:
|
|
55
|
+
|
|
56
|
+
1. user visits a page
|
|
57
|
+
2. `render_async` makes an AJAX request on the controller action
|
|
22
58
|
3. controller renders a partial
|
|
23
|
-
4.
|
|
59
|
+
4. partial renders in the place where you put `render_async` view helper
|
|
24
60
|
|
|
25
|
-
JavaScript is injected into `<%= content_for :render_async %>` so you choose
|
|
61
|
+
JavaScript is injected straight into `<%= content_for :render_async %>` so you choose
|
|
26
62
|
where to put it.
|
|
27
63
|
|
|
28
|
-
|
|
64
|
+
:mega: P.S. Join our [Discord channel](https://discord.gg/SPfbeRm) for help and discussion, and let's make `render_async` even better!
|
|
65
|
+
|
|
66
|
+
## :package: Installation
|
|
67
|
+
|
|
29
68
|
Add this line to your application's Gemfile:
|
|
30
69
|
|
|
31
70
|
```ruby
|
|
@@ -36,14 +75,14 @@ And then execute:
|
|
|
36
75
|
|
|
37
76
|
$ bundle install
|
|
38
77
|
|
|
39
|
-
## Usage
|
|
78
|
+
## :hammer: Usage
|
|
40
79
|
|
|
41
80
|
1. Include `render_async` view helper somewhere in your views (e.g. `app/views/comments/show.html.erb`):
|
|
42
81
|
```erb
|
|
43
82
|
<%= render_async comment_stats_path %>
|
|
44
83
|
```
|
|
45
84
|
|
|
46
|
-
2. Then create a route
|
|
85
|
+
2. Then create a route for it `config/routes.rb`:
|
|
47
86
|
```ruby
|
|
48
87
|
get :comment_stats, controller: :comments
|
|
49
88
|
```
|
|
@@ -69,7 +108,7 @@ And then execute:
|
|
|
69
108
|
<%= content_for :render_async %>
|
|
70
109
|
```
|
|
71
110
|
|
|
72
|
-
## Advanced usage
|
|
111
|
+
## :hammer_and_wrench: Advanced usage
|
|
73
112
|
|
|
74
113
|
Advanced usage includes information on different options, such as:
|
|
75
114
|
|
|
@@ -79,15 +118,23 @@ Advanced usage includes information on different options, such as:
|
|
|
79
118
|
- [Passing in an HTML element name](#passing-in-an-html-element-name)
|
|
80
119
|
- [Passing in a placeholder](#passing-in-a-placeholder)
|
|
81
120
|
- [Passing in an event name](#passing-in-an-event-name)
|
|
121
|
+
- [Using default events](#using-default-events)
|
|
122
|
+
- [Refreshing the partial](#refreshing-the-partial)
|
|
82
123
|
- [Retry on failure](#retry-on-failure)
|
|
124
|
+
- [Retry after some time](#retry-after-some-time)
|
|
125
|
+
- [Toggle event](#toggle-event)
|
|
126
|
+
- [Control polling with a toggle](#control-polling-with-a-toggle)
|
|
83
127
|
- [Polling](#polling)
|
|
128
|
+
- [Controlled polling](#controlled-polling)
|
|
84
129
|
- [Handling errors](#handling-errors)
|
|
85
130
|
- [Caching](#caching)
|
|
86
131
|
- [Doing non-GET requests](#doing-non-get-requests)
|
|
87
132
|
- [Using with Turbolinks](#using-with-turbolinks)
|
|
133
|
+
- [Using with Turbo](#using-with-turbo)
|
|
88
134
|
- [Using with respond_to and JS format](#using-with-respond_to-and-js-format)
|
|
89
|
-
- [Nested
|
|
90
|
-
- [
|
|
135
|
+
- [Nested async renders](#nested-async-renders)
|
|
136
|
+
- [Customizing the content_for name](#customizing-the-content_for-name)
|
|
137
|
+
- [Configuration options](#configuration-options)
|
|
91
138
|
|
|
92
139
|
### Passing in a container ID
|
|
93
140
|
|
|
@@ -128,27 +175,32 @@ Rendered code in the view:
|
|
|
128
175
|
|
|
129
176
|
### Passing in HTML options
|
|
130
177
|
|
|
131
|
-
`render_async` can accept `html_options`
|
|
178
|
+
`render_async` can accept `html_options` as a hash.
|
|
132
179
|
`html_options` is an optional hash that gets passed to a Rails'
|
|
133
180
|
`javascript_tag`, to drop HTML tags into the `script` element.
|
|
134
181
|
|
|
135
|
-
Example of utilizing `html_options` with a
|
|
182
|
+
Example of utilizing `html_options` with a [nonce](https://edgeguides.rubyonrails.org/security.html#content-security-policy):
|
|
183
|
+
|
|
136
184
|
```erb
|
|
137
|
-
<%= render_async users_path, nonce:
|
|
185
|
+
<%= render_async users_path, html_options: { nonce: true } %>
|
|
138
186
|
```
|
|
139
187
|
|
|
140
188
|
Rendered code in the view:
|
|
141
189
|
```html
|
|
142
|
-
<
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
<script nonce="lWaaV6eYicpt+oyOfcShYINsz0b70iR+Q1mohZqNaag=">
|
|
190
|
+
<script nonce="2x012CYGxKgM8qAApxRHxA==">
|
|
146
191
|
//<![CDATA[
|
|
147
192
|
...
|
|
148
193
|
//]]>
|
|
149
194
|
</script>
|
|
195
|
+
|
|
196
|
+
...
|
|
197
|
+
|
|
198
|
+
<div id="render_async_18b8a6cd161499117471" class="">
|
|
199
|
+
</div>
|
|
150
200
|
```
|
|
151
201
|
|
|
202
|
+
> :bulb: You can enable `nonce` to be set everywhere by using [configuration option](#configuration-options) render_async provides.
|
|
203
|
+
|
|
152
204
|
### Passing in an HTML element name
|
|
153
205
|
|
|
154
206
|
`render_async` can take in an HTML element name, allowing you to control
|
|
@@ -206,6 +258,9 @@ event after it's done with fetching and rendering request content to HTML.
|
|
|
206
258
|
This can be useful to have if you want to add some JavaScript functionality
|
|
207
259
|
after your partial is loaded through `render_async`.
|
|
208
260
|
|
|
261
|
+
You can also access the associated container (DOM node) in the event object
|
|
262
|
+
that gets emitted.
|
|
263
|
+
|
|
209
264
|
Example of passing it to `render_async`:
|
|
210
265
|
```erb
|
|
211
266
|
<%= render_async users_path, event_name: "users-loaded" %>
|
|
@@ -225,15 +280,77 @@ Rendered code in view:
|
|
|
225
280
|
</script>
|
|
226
281
|
```
|
|
227
282
|
|
|
228
|
-
Then, in your
|
|
283
|
+
Then, in your JavaScript code, you could do something like this:
|
|
229
284
|
```javascript
|
|
230
|
-
document.addEventListener("users-loaded", function() {
|
|
231
|
-
console.log("Users have loaded!");
|
|
285
|
+
document.addEventListener("users-loaded", function(event) {
|
|
286
|
+
console.log("Users have loaded!", event.container); // Access the container which loaded the users
|
|
232
287
|
});
|
|
233
288
|
```
|
|
234
289
|
|
|
235
|
-
|
|
236
|
-
|
|
290
|
+
> :bulb: Dispatching events is also supported for older browsers that don't support Event constructor.
|
|
291
|
+
|
|
292
|
+
### Using default events
|
|
293
|
+
|
|
294
|
+
`render_async` will fire the event `render_async_load` when an async partial
|
|
295
|
+
has loaded and rendered on the page.
|
|
296
|
+
|
|
297
|
+
In case there is an error, the event `render_async_error` will fire instead.
|
|
298
|
+
|
|
299
|
+
This event will fire for all `render_async` partials on the page. For every
|
|
300
|
+
event, the associated container (DOM node) will be passed along.
|
|
301
|
+
|
|
302
|
+
This can be useful to apply JavaScript to content loaded after the page is
|
|
303
|
+
ready.
|
|
304
|
+
|
|
305
|
+
Example of using events:
|
|
306
|
+
|
|
307
|
+
```js
|
|
308
|
+
// Vanilla javascript
|
|
309
|
+
document.addEventListener('render_async_load', function(event) {
|
|
310
|
+
console.log('Async partial loaded in this container:', event.container);
|
|
311
|
+
});
|
|
312
|
+
document.addEventListener('render_async_error', function(event) {
|
|
313
|
+
console.log('Async partial could not load in this container:', event.container);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// with jQuery
|
|
317
|
+
$(document).on('render_async_load', function(event) {
|
|
318
|
+
console.log('Async partial loaded in this container:', event.container);
|
|
319
|
+
});
|
|
320
|
+
$(document).on('render_async_error', function(event) {
|
|
321
|
+
console.log('Async partial could not load in this container:', event.container);
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Refreshing the partial
|
|
326
|
+
|
|
327
|
+
`render_async` lets you refresh (reload) the partial by letting you dispatch
|
|
328
|
+
the 'refresh' event on the `render_async`'s container. An example:
|
|
329
|
+
|
|
330
|
+
```erb
|
|
331
|
+
<%= render_async comments_path,
|
|
332
|
+
container_id: 'refresh-me',
|
|
333
|
+
replace_container: false %>
|
|
334
|
+
|
|
335
|
+
<button id="refresh-button">Refresh comments</button>
|
|
336
|
+
|
|
337
|
+
<script>
|
|
338
|
+
var button = document.getElementById('refresh-button')
|
|
339
|
+
var container = document.getElementById('refresh-me');
|
|
340
|
+
|
|
341
|
+
button.addEventListener('click', function() {
|
|
342
|
+
var event = new Event('refresh');
|
|
343
|
+
|
|
344
|
+
// Dispatch 'refresh' on the render_async container
|
|
345
|
+
container.dispatchEvent(event)
|
|
346
|
+
})
|
|
347
|
+
</script>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
If you follow the example above, when you click "Refresh comments" button,
|
|
351
|
+
`render_async` will trigger again and reload the `comments_path`.
|
|
352
|
+
|
|
353
|
+
> :bulb: Note that you need to pass `replace_container: false` so you can later dispatch an event on that container.
|
|
237
354
|
|
|
238
355
|
### Retry on failure
|
|
239
356
|
|
|
@@ -245,17 +362,120 @@ this:
|
|
|
245
362
|
<%= render_async users_path, retry_count: 5, error_message: "Couldn't fetch it" %>
|
|
246
363
|
```
|
|
247
364
|
|
|
248
|
-
Now render_async will retry `users_path` for 5 times. If it
|
|
365
|
+
Now render_async will retry `users_path` for 5 times. If it succeeds in
|
|
249
366
|
between, it will stop with dispatching requests. If it fails after 5 times,
|
|
250
367
|
it will show an [error message](#handling-errors) which you need to specify.
|
|
251
368
|
|
|
252
369
|
This can show useful when you know your requests often fail, and you don't want
|
|
253
370
|
to refresh the whole page just to retry them.
|
|
254
371
|
|
|
372
|
+
#### Retry after some time
|
|
373
|
+
|
|
374
|
+
If you want to retry requests but with some delay in between the calls, you can
|
|
375
|
+
pass a `retry_delay` option together with `retry_count` like so:
|
|
376
|
+
|
|
377
|
+
```erb
|
|
378
|
+
<%= render_async users_path,
|
|
379
|
+
retry_count: 5,
|
|
380
|
+
retry_delay: 2000 %>
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
This will make `render_async` wait for 2 seconds before retrying after each
|
|
384
|
+
failure. In the end, if the request is still failing after 5th time, it will
|
|
385
|
+
dispatch a [default error event](#using-default-events).
|
|
386
|
+
|
|
387
|
+
> :candy: If you are catching an event after an error, you can get `retryCount` from
|
|
388
|
+
the event. `retryCount` will have the number of retries it took before the event was dispatched.
|
|
389
|
+
|
|
390
|
+
Here is an example on how to get `retryCount`:
|
|
391
|
+
|
|
392
|
+
```erb
|
|
393
|
+
<%= render_async users_path,
|
|
394
|
+
retry_count: 5,
|
|
395
|
+
retry_delay: 2000,
|
|
396
|
+
error_event_name: 'it-failed-badly' %>
|
|
397
|
+
|
|
398
|
+
<script>
|
|
399
|
+
document.addEventListener('it-failed-badly', function(event) {
|
|
400
|
+
console.log("Request failed after " + event.retryCount + " tries!")
|
|
401
|
+
});
|
|
402
|
+
</script>
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
If you need to pass retry count to the backend, you can pass `retry_count_header` in `render_async`'s options:
|
|
406
|
+
|
|
407
|
+
```erb
|
|
408
|
+
<%= render_async users_path,
|
|
409
|
+
retry_count: 5,
|
|
410
|
+
retry_count_header: 'Retry-Count-Current' %>
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
And then in controller you can read the value from request headers.
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
request.headers['Retry-Count-Current']&.to_i
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Toggle event
|
|
420
|
+
|
|
421
|
+
You can trigger `render_async` loading by clicking or doing another event to a
|
|
422
|
+
certain HTML element. You can do this by passing in a selector and an event
|
|
423
|
+
name which will trigger `render_async`. If you don't specify an event name, the
|
|
424
|
+
default event that will trigger `render_async` will be 'click' event. You can
|
|
425
|
+
do this by doing the following:
|
|
426
|
+
|
|
427
|
+
```erb
|
|
428
|
+
<a href='#' id='comments-button'>Load comments</a>
|
|
429
|
+
<%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } %>
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
This will trigger `render_async` to load the `comments_path` when you click the `#comments-button` element.
|
|
433
|
+
If you want to remove an event once it's triggered, you can pass `once: true` in the toggle options.
|
|
434
|
+
The `once` option is false (`nil`) by default.
|
|
435
|
+
|
|
436
|
+
You can also pass in a placeholder before the `render_async` is triggered. That
|
|
437
|
+
way, the element that started `render_async` logic will be removed after the
|
|
438
|
+
request has been completed. You can achieve this behaviour with something like this:
|
|
439
|
+
|
|
440
|
+
```erb
|
|
441
|
+
<%= render_async comments_path, toggle: { selector: '#comments-button', event: :click } do %>
|
|
442
|
+
<a href='#' id='comments-button'>Load comments</a>
|
|
443
|
+
<% end %>
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### Control polling with a toggle
|
|
447
|
+
|
|
448
|
+
Also, you can mix interval and toggle features. This way, you can turn polling
|
|
449
|
+
on, and off by clicking the "Load comments" button. In order to do this, you need to
|
|
450
|
+
pass `toggle` and `interval` arguments to `render_async` call like this:
|
|
451
|
+
|
|
452
|
+
```erb
|
|
453
|
+
<a href='#' id='comments-button'>Load comments</a>
|
|
454
|
+
<%= render_async comments_path, toggle: { selector: '#comments-button', event: :click }, interval: 2000 %>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
If you want `render_async` to render the request on load, you can pass `start:
|
|
458
|
+
true`. Passing the `start` option inside the `toggle` hash will trigger
|
|
459
|
+
`render_async` on page load. You can then toggle off polling by interacting
|
|
460
|
+
with the element you specified. An example:
|
|
461
|
+
|
|
462
|
+
```erb
|
|
463
|
+
<a href='#' id='comments-button'>Toggle comments loading</a>
|
|
464
|
+
<%= render_async comments_path,
|
|
465
|
+
toggle: { selector: '#comments-button',
|
|
466
|
+
event: :click,
|
|
467
|
+
start: true },
|
|
468
|
+
interval: 2000 %>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
In the example above, the comments will load as soon as the page is rendered.
|
|
472
|
+
Then, you can stop polling for comments by clicking the "Toggle comments
|
|
473
|
+
loading" button.
|
|
474
|
+
|
|
255
475
|
### Polling
|
|
256
476
|
|
|
257
477
|
You can call `render_async` with interval argument. This will make render_async
|
|
258
|
-
call specified path at specified interval.
|
|
478
|
+
call specified path at the specified interval.
|
|
259
479
|
|
|
260
480
|
By doing this:
|
|
261
481
|
```erb
|
|
@@ -265,15 +485,65 @@ You are telling `render_async` to fetch comments_path every 5 seconds.
|
|
|
265
485
|
|
|
266
486
|
This can be handy if you want to enable polling for a specific URL.
|
|
267
487
|
|
|
268
|
-
|
|
269
|
-
will remain in HTML tree
|
|
270
|
-
You can handle how that container element is rendered and its style by
|
|
271
|
-
[passing in an HTML element name](#passing-in-an-html-element-name) and
|
|
272
|
-
[HTML element class](#passing-in-a-container-class-name).
|
|
488
|
+
> :warning: By passing interval to `render_async`, the initial container element
|
|
489
|
+
> will remain in the HTML tree and it will not be replaced with request response.
|
|
490
|
+
> You can handle how that container element is rendered and its style by
|
|
491
|
+
> [passing in an HTML element name](#passing-in-an-html-element-name) and
|
|
492
|
+
> [HTML element class](#passing-in-a-container-class-name).
|
|
493
|
+
|
|
494
|
+
### Controlled polling
|
|
495
|
+
|
|
496
|
+
You can controller `render_async` [polling](#polling) in 2 manners.
|
|
497
|
+
First one is pretty simple, and it involves using the [toggle](#toggle-event)
|
|
498
|
+
feature. To do this, you can follow instructions in the
|
|
499
|
+
[control polling with a toggle section](#control-polling-with-a-toggle).
|
|
500
|
+
|
|
501
|
+
The second option is more advanced and it involves emitting events to the `render_async`'s
|
|
502
|
+
container element. From your code, you can emit the following events:
|
|
503
|
+
- 'async-stop' - this will stop polling
|
|
504
|
+
- 'async-start' - this will start polling.
|
|
505
|
+
|
|
506
|
+
> :bulb: Please note that events need to be dispatched to a render_async container.
|
|
507
|
+
|
|
508
|
+
An example of how you can do this looks like this:
|
|
509
|
+
|
|
510
|
+
```erb
|
|
511
|
+
<%= render_async wave_render_async_path,
|
|
512
|
+
container_id: 'controllable-interval', # set container_id so we can get it later easily
|
|
513
|
+
interval: 3000 %>
|
|
514
|
+
|
|
515
|
+
<button id='stop-polling'>Stop polling</button>
|
|
516
|
+
<button id='start-polling'>Start polling</button>
|
|
517
|
+
|
|
518
|
+
<script>
|
|
519
|
+
var container = document.getElementById('controllable-interval')
|
|
520
|
+
var stopPolling = document.getElementById('stop-polling')
|
|
521
|
+
var startPolling = document.getElementById('start-polling')
|
|
522
|
+
|
|
523
|
+
var triggerEventOnContainer = function(eventName) {
|
|
524
|
+
var event = new Event(eventName);
|
|
525
|
+
|
|
526
|
+
container.dispatchEvent(event)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
stopPolling.addEventListener('click', function() {
|
|
530
|
+
container.innerHTML = '<p>Polling stopped</p>'
|
|
531
|
+
triggerEventOnContainer('async-stop')
|
|
532
|
+
})
|
|
533
|
+
startPolling.addEventListener('click', function() {
|
|
534
|
+
triggerEventOnContainer('async-start')
|
|
535
|
+
})
|
|
536
|
+
</script>
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
We are rendering two buttons - "Stop polling" and "Start polling". Then, we
|
|
540
|
+
attach an event listener to catch any clicking on the buttons. When the buttons
|
|
541
|
+
are clicked, we either stop the polling or start the polling, depending on which
|
|
542
|
+
button a user clicks.
|
|
273
543
|
|
|
274
544
|
### Handling errors
|
|
275
545
|
|
|
276
|
-
`render_async`
|
|
546
|
+
`render_async` lets you handle errors by allowing you to pass in `error_message`
|
|
277
547
|
and `error_event_name`.
|
|
278
548
|
|
|
279
549
|
- `error_message`
|
|
@@ -319,10 +589,10 @@ Then, in the partial (e.g. `app/views/comments/_comment_stats.html.erb`):
|
|
|
319
589
|
<% end %>
|
|
320
590
|
```
|
|
321
591
|
|
|
322
|
-
|
|
323
|
-
|
|
592
|
+
- The first time the page renders, it will make the AJAX call.
|
|
593
|
+
- Any other times (until the cache expires), it will render from cache
|
|
324
594
|
instantly, without making the AJAX call.
|
|
325
|
-
|
|
595
|
+
- You can expire cache simply by passing `:expires_in` in your view where
|
|
326
596
|
you cache the partial
|
|
327
597
|
|
|
328
598
|
### Doing non-GET requests
|
|
@@ -351,7 +621,7 @@ away from, and then back to, a page with a `render_async` call on it. This will
|
|
|
351
621
|
likely show up as an empty div.
|
|
352
622
|
|
|
353
623
|
If you're using Turbolinks 5 or higher, you can resolve this by setting Turbolinks
|
|
354
|
-
|
|
624
|
+
configuration of `render_async` to true:
|
|
355
625
|
|
|
356
626
|
```rb
|
|
357
627
|
RenderAsync.configure do |config|
|
|
@@ -360,19 +630,49 @@ end
|
|
|
360
630
|
```
|
|
361
631
|
|
|
362
632
|
This way, you're not breaking Turbolinks flow of loading or reloading a page.
|
|
363
|
-
It
|
|
633
|
+
It is more efficient than the next option below.
|
|
364
634
|
|
|
365
635
|
Another option:
|
|
366
636
|
If you want, you can tell Turbolinks to reload your `render_async` call as follows:
|
|
367
637
|
|
|
368
638
|
```erb
|
|
369
|
-
<%= render_async events_path, 'data-turbolinks-track': 'reload' %>
|
|
639
|
+
<%= render_async events_path, html_options: { 'data-turbolinks-track': 'reload' } %>
|
|
370
640
|
```
|
|
371
641
|
|
|
372
642
|
This will reload the whole page with Turbolinks.
|
|
373
643
|
|
|
374
|
-
|
|
375
|
-
the `<
|
|
644
|
+
> :bulb: If Turbolinks is misbehaving in some way, make sure to put `<%= content_for :render_async %>` in your base view file in
|
|
645
|
+
the `<body>` and not the `<head>`.
|
|
646
|
+
|
|
647
|
+
### Using with Turbo
|
|
648
|
+
|
|
649
|
+
On Turbo applications, you may experience caching issues when navigating
|
|
650
|
+
away from, and then back to, a page with a `render_async` call on it. This will
|
|
651
|
+
likely show up as an empty div.
|
|
652
|
+
|
|
653
|
+
If you're using Turbo, you can resolve this by setting Turbo
|
|
654
|
+
configuration of `render_async` to true:
|
|
655
|
+
|
|
656
|
+
```rb
|
|
657
|
+
RenderAsync.configure do |config|
|
|
658
|
+
config.turbo = true # Enable this option if you are using Turbo
|
|
659
|
+
end
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
This way, you're not breaking Turbos flow of loading or reloading a page.
|
|
663
|
+
It is more efficient than the next option below.
|
|
664
|
+
|
|
665
|
+
Another option:
|
|
666
|
+
If you want, you can tell Turbo to reload your `render_async` call as follows:
|
|
667
|
+
|
|
668
|
+
```erb
|
|
669
|
+
<%= render_async events_path, html_options: { 'data-turbo-track': 'reload' } %>
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
This will reload the whole page with Turbo.
|
|
673
|
+
|
|
674
|
+
> :bulb: If Turbo is misbehaving in some way, make sure to put `<%= content_for :render_async %>` in your base view file in
|
|
675
|
+
the `<body>` and not the `<head>`.
|
|
376
676
|
|
|
377
677
|
### Using with respond_to and JS format
|
|
378
678
|
|
|
@@ -391,7 +691,7 @@ def comment_stats
|
|
|
391
691
|
end
|
|
392
692
|
```
|
|
393
693
|
|
|
394
|
-
When you do this, Rails will
|
|
694
|
+
When you do this, Rails will sometimes set the response's `Content-Type` header
|
|
395
695
|
to `text/javascript`. This causes the partial not to be rendered in the HTML.
|
|
396
696
|
This usually happens when there's browser caching.
|
|
397
697
|
|
|
@@ -402,7 +702,7 @@ render call:
|
|
|
402
702
|
render partial: "comment_stats", content_type: 'text/html'
|
|
403
703
|
```
|
|
404
704
|
|
|
405
|
-
### Nested
|
|
705
|
+
### Nested async renders
|
|
406
706
|
|
|
407
707
|
It is possible to nest async templates within other async templates. When doing
|
|
408
708
|
so, another `content_for` is required to ensure the JavaScript needed to load
|
|
@@ -429,7 +729,20 @@ For example:
|
|
|
429
729
|
<%= content_for :render_async %>
|
|
430
730
|
```
|
|
431
731
|
|
|
432
|
-
###
|
|
732
|
+
### Customizing the content_for name
|
|
733
|
+
|
|
734
|
+
The `content_for` name may be customized by passing the `content_for_name`
|
|
735
|
+
option to `render_async`. This option is especially useful when doing [nested async
|
|
736
|
+
renders](#nested-async-renders) to better control the location of the injected JavaScript.
|
|
737
|
+
|
|
738
|
+
For example:
|
|
739
|
+
```erb
|
|
740
|
+
<%= render_async comment_stats_path, content_for_name: :render_async_comment_stats %>
|
|
741
|
+
|
|
742
|
+
<%= content_for :render_async_comment_stats %>
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Configuration options
|
|
433
746
|
|
|
434
747
|
`render_async` renders Vanilla JS (regular JavaScript, non-jQuery code)
|
|
435
748
|
**by default** in order to fetch the request from the server.
|
|
@@ -439,10 +752,14 @@ so.
|
|
|
439
752
|
|
|
440
753
|
You can configure it by doing the following anywhere before you call
|
|
441
754
|
`render_async`:
|
|
755
|
+
|
|
442
756
|
```rb
|
|
443
757
|
RenderAsync.configure do |config|
|
|
444
|
-
config.jquery = true # This will render jQuery code, and skip Vanilla JS code
|
|
445
|
-
config.turbolinks =
|
|
758
|
+
config.jquery = true # This will render jQuery code, and skip Vanilla JS code. The default value is false.
|
|
759
|
+
config.turbolinks = true # Enable this option if you are using Turbolinks 5+. The default value is false.
|
|
760
|
+
config.turbo = true # Enable this option if you are using Turbo. The default value is false.
|
|
761
|
+
config.replace_container = false # Set to false if you want to keep the placeholder div element from render_async. The default value is true.
|
|
762
|
+
config.nonces = true # Set to true if you want render_async's javascript_tag always to receive nonce: true. The default value is false.
|
|
446
763
|
end
|
|
447
764
|
```
|
|
448
765
|
|
|
@@ -452,17 +769,34 @@ Also, you can do it like this:
|
|
|
452
769
|
RenderAsync.configuration.jquery = true
|
|
453
770
|
```
|
|
454
771
|
|
|
455
|
-
|
|
772
|
+
Aside from configuring whether the gem relies on jQuery or VanillaJS, you can
|
|
773
|
+
configure other options:
|
|
774
|
+
|
|
775
|
+
- `turbolinks` option - If you are using Turbolinks 5+, you should enable this option since it supports Turbolinks way of loading data. The default value for this option is false.
|
|
776
|
+
- `turbo` option - If you are using Turbo, you should enable this option since it supports Turbo way of loading data. The default value for this option is false.
|
|
777
|
+
- `replace_container` option - If you want render_async to replace its container with the request response, turn this on. You can turn this on globally for all render_async calls, but if you use this option in a specific render_async call, it will override the global configuration. The default value is true.
|
|
778
|
+
- `nonces` - If you need to pass in `nonce: true` to the `javascript_tag` in your application, it might make sense for you to turn this on globally for all render_async calls. To read more about nonces, check out [Rails' official guide on security](https://edgeguides.rubyonrails.org/security.html). The default value is false.
|
|
779
|
+
|
|
780
|
+
## :hammer_and_pick: Development
|
|
456
781
|
|
|
457
782
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
458
783
|
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
|
459
|
-
prompt that will allow you to experiment.
|
|
784
|
+
prompt that will allow you to experiment. To run integration tests, use
|
|
785
|
+
`bin/integration-tests`. For more information, check out [CONTRIBUTING](.github/CONTRIBUTING.md) file, please.
|
|
786
|
+
|
|
787
|
+
Got any questions or comments about development (or anything else)?
|
|
788
|
+
Join [render_async's Discord channel](https://discord.gg/SPfbeRm)
|
|
789
|
+
and let's make `render_async` even better!
|
|
790
|
+
|
|
791
|
+
## :pray: Contributing
|
|
460
792
|
|
|
461
|
-
|
|
793
|
+
Check out [CONTRIBUTING](.github/CONTRIBUTING.md) file, please.
|
|
462
794
|
|
|
463
|
-
|
|
795
|
+
Got any issues or difficulties?
|
|
796
|
+
Join [render_async's Discord channel](https://discord.gg/SPfbeRm)
|
|
797
|
+
and let's make `render_async` even better!
|
|
464
798
|
|
|
465
|
-
## License
|
|
799
|
+
## :memo: License
|
|
466
800
|
|
|
467
801
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
468
802
|
|
|
@@ -472,10 +806,11 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
|
|
|
472
806
|
|
|
473
807
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
474
808
|
<!-- prettier-ignore -->
|
|
475
|
-
| [<img src="https://avatars2.githubusercontent.com/u/3028124?v=4" width="100px;"/><br /><sub><b>Nikola Δuza</b></sub>](
|
|
809
|
+
| [<img src="https://avatars2.githubusercontent.com/u/3028124?v=4" width="100px;"/><br /><sub><b>Nikola Δuza</b></sub>](https://nikolalsvk.github.io)<br />[π¬](#question-nikolalsvk "Answering Questions") [π»](https://github.com/renderedtext/render_async/commits?author=nikolalsvk "Code") [π](https://github.com/renderedtext/render_async/commits?author=nikolalsvk "Documentation") [π](#review-nikolalsvk "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/3866868?v=4" width="100px;"/><br /><sub><b>Colin</b></sub>](http://www.colinxfleming.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=colinxfleming "Code") [π](https://github.com/renderedtext/render_async/commits?author=colinxfleming "Documentation") [π‘](#example-colinxfleming "Examples") | [<img src="https://avatars2.githubusercontent.com/u/334273?v=4" width="100px;"/><br /><sub><b>Kasper Grubbe</b></sub>](http://kaspergrubbe.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=kaspergrubbe "Code") | [<img src="https://avatars2.githubusercontent.com/u/163584?v=4" width="100px;"/><br /><sub><b>Sai Ram Kunala</b></sub>](https://sairam.xyz/)<br />[π](https://github.com/renderedtext/render_async/commits?author=sairam "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/3065882?v=4" width="100px;"/><br /><sub><b>Josh Arnold</b></sub>](https://github.com/nightsurge)<br />[π»](https://github.com/renderedtext/render_async/commits?author=nightsurge "Code") [π](https://github.com/renderedtext/render_async/commits?author=nightsurge "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/107798?v=4" width="100px;"/><br /><sub><b>Elad Shahar</b></sub>](https://eladshahar.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=SaladFork "Code") [π‘](#example-SaladFork "Examples") | [<img src="https://avatars3.githubusercontent.com/u/232392?v=4" width="100px;"/><br /><sub><b>Sasha</b></sub>](http://www.revzin.co.il)<br />[π»](https://github.com/renderedtext/render_async/commits?author=sasharevzin "Code") [π](https://github.com/renderedtext/render_async/commits?author=sasharevzin "Documentation") |
|
|
476
810
|
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
477
|
-
| [<img src="https://avatars3.githubusercontent.com/u/50223?v=4" width="100px;"/><br /><sub><b>Ernest Surudo</b></sub>](http://elsurudo.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=elsurudo "Code") | [<img src="https://avatars1.githubusercontent.com/u/334809?v=4" width="100px;"/><br /><sub><b>Kurtis Rainbolt-Greene</b></sub>](https://kurtis.rainbolt-greene.online)<br />[π»](https://github.com/renderedtext/render_async/commits?author=krainboltgreene "Code") | [<img src="https://avatars2.githubusercontent.com/u/59744?v=4" width="100px;"/><br /><sub><b>Richard Schneeman</b></sub>](https://www.schneems.com)<br />[π](https://github.com/renderedtext/render_async/commits?author=schneems "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/75705?v=4" width="100px;"/><br /><sub><b>Richard Venneman</b></sub>](https://www.cityspotters.com)<br />[π](https://github.com/renderedtext/render_async/commits?author=richardvenneman "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/381395?v=4" width="100px;"/><br /><sub><b>Filipe W. Lima</b></sub>](https://github.com/filipewl)<br />[π](https://github.com/renderedtext/render_async/commits?author=filipewl "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/3135638?v=4" width="100px;"/><br /><sub><b>JesΓΊs Eduardo Clemens Chong</b></sub>](https://github.com/eclemens)<br />[π»](https://github.com/renderedtext/render_async/commits?author=eclemens "Code") | [<img src="https://avatars3.githubusercontent.com/u/1935686?v=4" width="100px;"/><br /><sub><b>RenΓ© KlaΔan</b></sub>](https://github.com/reneklacan)<br />[π»](https://github.com/renderedtext/render_async/commits?author=reneklacan "Code") |
|
|
478
|
-
| [<img src="https://avatars1.githubusercontent.com/u/1313442?v=4" width="100px;"/><br /><sub><b>Gil Gomes</b></sub>](http://gilgomes.com.br)<br />[π](https://github.com/renderedtext/render_async/commits?author=gil27 "Documentation") |
|
|
811
|
+
| [<img src="https://avatars3.githubusercontent.com/u/50223?v=4" width="100px;"/><br /><sub><b>Ernest Surudo</b></sub>](http://elsurudo.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=elsurudo "Code") | [<img src="https://avatars1.githubusercontent.com/u/334809?v=4" width="100px;"/><br /><sub><b>Kurtis Rainbolt-Greene</b></sub>](https://kurtis.rainbolt-greene.online)<br />[π»](https://github.com/renderedtext/render_async/commits?author=krainboltgreene "Code") | [<img src="https://avatars2.githubusercontent.com/u/59744?v=4" width="100px;"/><br /><sub><b>Richard Schneeman</b></sub>](https://www.schneems.com)<br />[π](https://github.com/renderedtext/render_async/commits?author=schneems "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/75705?v=4" width="100px;"/><br /><sub><b>Richard Venneman</b></sub>](https://www.cityspotters.com)<br />[π](https://github.com/renderedtext/render_async/commits?author=richardvenneman "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/381395?v=4" width="100px;"/><br /><sub><b>Filipe W. Lima</b></sub>](https://github.com/filipewl)<br />[π](https://github.com/renderedtext/render_async/commits?author=filipewl "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/3135638?v=4" width="100px;"/><br /><sub><b>JesΓΊs Eduardo Clemens Chong</b></sub>](https://github.com/eclemens)<br />[π»](https://github.com/renderedtext/render_async/commits?author=eclemens "Code") | [<img src="https://avatars3.githubusercontent.com/u/1935686?v=4" width="100px;"/><br /><sub><b>RenΓ© KlaΔan</b></sub>](https://github.com/reneklacan)<br />[π»](https://github.com/renderedtext/render_async/commits?author=reneklacan "Code") [π](https://github.com/renderedtext/render_async/commits?author=reneklacan "Documentation") |
|
|
812
|
+
| [<img src="https://avatars1.githubusercontent.com/u/1313442?v=4" width="100px;"/><br /><sub><b>Gil Gomes</b></sub>](http://gilgomes.com.br)<br />[π](https://github.com/renderedtext/render_async/commits?author=gil27 "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/6081795?v=4" width="100px;"/><br /><sub><b>Khoa Nguyen</b></sub>](https://github.com/ThanhKhoaIT)<br />[π»](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Code") [π](https://github.com/renderedtext/render_async/commits?author=ThanhKhoaIT "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/8645918?v=4" width="100px;"/><br /><sub><b>Preet Sethi</b></sub>](https://www.linkedin.com/in/preetsethila/)<br />[π»](https://github.com/renderedtext/render_async/commits?author=preetsethi "Code") | [<img src="https://avatars3.githubusercontent.com/u/11586335?v=4" width="100px;"/><br /><sub><b>fangxing</b></sub>](https://github.com/fffx)<br />[π»](https://github.com/renderedtext/render_async/commits?author=fffx "Code") | [<img src="https://avatars3.githubusercontent.com/u/1191418?v=4" width="100px;"/><br /><sub><b>Emmanuel Pire</b></sub>](http://blog.lipsumarium.com)<br />[π»](https://github.com/renderedtext/render_async/commits?author=lipsumar "Code") [π](https://github.com/renderedtext/render_async/commits?author=lipsumar "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/615509?v=4" width="100px;"/><br /><sub><b>Maxim Geerinck</b></sub>](https://github.com/maximgeerinck)<br />[π»](https://github.com/renderedtext/render_async/commits?author=maximgeerinck "Code") | [<img src="https://avatars1.githubusercontent.com/u/251706?v=4" width="100px;"/><br /><sub><b>Don</b></sub>](https://github.com/vanboom)<br />[π»](https://github.com/renderedtext/render_async/commits?author=vanboom "Code") |
|
|
813
|
+
| [<img src="https://avatars0.githubusercontent.com/u/998682?v=4" width="100px;"/><br /><sub><b>villu164</b></sub>](https://github.com/villu164)<br />[π](https://github.com/renderedtext/render_async/commits?author=villu164 "Documentation") | [<img src="https://avatars.githubusercontent.com/u/11203679?v=4" width="100px;"/><br /><sub><b>Mitchell Buckley</b></sub>](https://github.com/Mbuckley0)<br />[π»](https://github.com/renderedtext/render_async/commits?author=Mbuckley0 "Code") [π](https://github.com/renderedtext/render_async/commits?author=Mbuckley0 "Documentation") | [<img src="https://avatars.githubusercontent.com/u/15371677?v=4" width="100px;"/><br /><sub><b>yhirano55</b></sub>](https://github.com/yhirano55)<br />[π»](https://github.com/renderedtext/render_async/commits?author=yhirano55 "Code") [π](https://github.com/renderedtext/render_async/commits?author=yhirano55 "Documentation") |
|
|
479
814
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
480
815
|
|
|
481
816
|
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|