591 search results for Turbo

Turbo-Friendly JavaScript

The biggest gotcha with Turbo Drive is JavaScript. And that's for one simple reason: suddenly there are no full page refreshes! And... a lot of JavaScript is written to expect that behavior. Let's see how some classic ...

6:56
Turbo Stream for Instant Review Update

... returning a turbo stream: reviews.stream.html.twig is responsible for updating both spots. Cool, but remember that the reviews list and review form live inside of a turbo frame. And so, before we started messing around ...

8:50
Review this Product in a turbo-frame

... right here. There is nothing fancy about this: this is a normal HTML form with no custom JavaScript and no turbo frame. And, mostly, it works great! Fill out the form... and submit. Ooh, that's smooth... just because ...

7:50
Prevent a turbo-frame from Rendering

... details and submit. Oh! The modal did close... but we have an error in the console! Response has no matching <turbo-frame id="product-info"> element. Ah, the problem is that, even though we closed the modal, the turbo ...

6:34
Blog
Live Components Turbo Streams Navigating a Turbo Frame

Recently, we received a fascinating question, summarized as: Suppose I submit a Live component to a LiveAction and redirect from there. How can I make this navigate a <turbo-frame> instead of the full page? Let's learn ...

61 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 2
const TurboHelper = class {
constructor() {
document.addEventListener('turbo:before-cache', () => {
this.closeModal();
this.closeSweetalert();
});
document.addEventListener('turbo:render', () => {
this.initializeWeatherWidget();
});
document.addEventListener('turbo:visit', () => {
// fade out the old body
document.body.classList.add('turbo-loading');
});
document.addEventListener('turbo:before-render', (event) => {
// when we are *about* to render, start us faded out
event.detail.newBody.classList.add('turbo-loading');
});
document.addEventListener('turbo:render', () => {
// after rendering, we first allow the .turbo-loaded to set the low opacity
// THEN, 10ms later, we remove the turbo-loaded class, which allows the fade in
setTimeout(() => {
document.body.classList.remove('turbo-loading');
}, 10);
});
}
// ... lines 30 - 61
See Code Block in Script
91 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 18
document.addEventListener('turbo:before-render', (event) => {
if (this.isPreviewRendered()) {
// this is a preview that has been instantly swapped
// remove .turbo-loading so the preview starts fully opaque
event.detail.newBody.classList.remove('turbo-loading');
// start fading out 1 frame later after opacity starts full
requestAnimationFrame(() => {
document.body.classList.add('turbo-loading');
});
} else {
const isRestoration = event.detail.newBody.classList.contains('turbo-loading');
if (isRestoration) {
// this is a restoration (back button). Remove the class
// so it simply starts with full opacity
event.detail.newBody.classList.remove('turbo-loading');
return;
}
// when we are *about* to render a fresh page
// we should already be faded out, so start us faded out
event.detail.newBody.classList.add('turbo-loading');
}
});
// ... lines 44 - 91
See Code Block in Script
Blog
Live Stream 9 Turbo 8 Live Components Challenges in Morphing

... In this week's live stream, we dive Turbo 8, view transitions, and "morphing": the key tech behind LiveComponents & a new feature in Turbo 8. We work on how to make our Stimulus controllers morph-ready, including the UX ...

61 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 17
document.addEventListener('turbo:before-render', (event) => {
// when we are *about* to render, start us faded out
event.detail.newBody.classList.add('turbo-loading');
});
document.addEventListener('turbo:render', () => {
// after rendering, we first allow the turbo-loading class to set the low opacity
// THEN, one frame later, we remove the turbo-loading class, which allows the fade in
requestAnimationFrame(() => {
document.body.classList.remove('turbo-loading');
});
});
// ... lines 29 - 61
See Code Block in Script
81 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 18
document.addEventListener('turbo:before-render', (event) => {
if (this.isPreviewRendered()) {
// this is a preview that has been instantly swapped
// remove .turbo-loading so the preview starts fully opaque
event.detail.newBody.classList.remove('turbo-loading');
// start fading out 1 frame later after opacity starts full
requestAnimationFrame(() => {
document.body.classList.add('turbo-loading');
});
} else {
// when we are *about* to render a fresh page
// we should already be faded out, so start us faded out
event.detail.newBody.classList.add('turbo-loading');
}
});
// ... lines 34 - 81
See Code Block in Script
95 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 3
constructor() {
document.addEventListener('turbo:before-cache', () => {
this.closeModal();
this.closeSweetalert();
});
document.addEventListener('turbo:render', () => {
this.initializeWeatherWidget();
});
this.initializeTransitions();
}
// ... lines 16 - 47
initializeTransitions() {
document.addEventListener('turbo:visit', () => {
// fade out the old body
document.body.classList.add('turbo-loading');
});
document.addEventListener('turbo:before-render', (event) => {
if (this.isPreviewRendered()) {
// this is a preview that has been instantly swapped
// remove .turbo-loading so the preview starts fully opaque
event.detail.newBody.classList.remove('turbo-loading');
// start fading out 1 frame later after opacity starts full
requestAnimationFrame(() => {
document.body.classList.add('turbo-loading');
});
} else {
const isRestoration = event.detail.newBody.classList.contains('turbo-loading');
if (isRestoration) {
// this is a restoration (back button). Remove the class
// so it simply starts with full opacity
event.detail.newBody.classList.remove('turbo-loading');
return;
}
// when we are *about* to render a fresh page
// we should already be faded out, so start us faded out
event.detail.newBody.classList.add('turbo-loading');
}
});
document.addEventListener('turbo:render', () => {
if (!this.isPreviewRendered()) {
// if this is a preview, then we do nothing: stay faded out
// after rendering the REAL page, we first allow the .turbo-loading to
// instantly start the page at lower opacity. THEN remove the class
// one frame later, which allows the fade in
requestAnimationFrame(() => {
document.body.classList.remove('turbo-loading');
});
}
});
}
// ... lines 92 - 95
See Code Block in Script
101 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 4
document.addEventListener('turbo:before-cache', () => {
this.closeModal();
this.closeSweetalert();
this.reenableSubmitButtons();
});
// ... lines 10 - 90
reenableSubmitButtons() {
document.querySelectorAll('.turbo-submit-disabled').forEach((button) => {
button.toggleAttribute('disabled', false);
button.classList.remove('turbo-submit-disabled');
});
}
// ... lines 98 - 101
See Code Block in Script
145 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 107
beforeFetchRequest(event) {
const frameId = event.detail.fetchOptions.headers['Turbo-Frame'];
if (!frameId) {
return;
}
const frame = document.querySelector(`#${frameId}`);
if (!frame || !frame.dataset.turboFormRedirect) {
return;
}
event.detail.fetchOptions.headers['Turbo-Frame-Redirect'] = 1;
}
// ... lines 122 - 145
See Code Block in Script
81 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 33
document.addEventListener('turbo:render', () => {
if (!this.isPreviewRendered()) {
// if this is a preview, then we do nothing: stay faded out
// after rendering the REAL page, we first allow the .turbo-loading to
// instantly start the page at lower opacity. THEN remove the class
// one frame later, which allows the fade in
requestAnimationFrame(() => {
document.body.classList.remove('turbo-loading');
});
}
});
// ... lines 45 - 81
See Code Block in Script
81 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 73
isPreviewRendered() {
return document.documentElement.hasAttribute('data-turbo-preview');
}
}
// ... lines 79 - 81
See Code Block in Script
122 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 3
const TurboHelper = class {
// ... lines 5 - 115
getCurrentFrame() {
return document.querySelector('turbo-frame[busy]');
}
}
// ... lines 120 - 122
See Code Block in Script
101 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 9
document.addEventListener('turbo:submit-start', (event) => {
const submitter = event.detail.formSubmission.submitter;
submitter.toggleAttribute('disabled', true);
submitter.classList.add('turbo-submit-disabled');
})
// ... lines 17 - 101
See Code Block in Script
137 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 3
const TurboHelper = class {
// ... lines 5 - 122
beforeFetchResponse(event) {
const fetchResponse = event.detail.fetchResponse;
const redirectLocation = fetchResponse.response.headers.get('Turbo-Location');
if (!redirectLocation) {
return;
}
event.preventDefault();
Turbo.clearCache();
Turbo.visit(redirectLocation);
}
}
// ... lines 135 - 137
See Code Block in Script
61 lines | assets/turbo/turbo-helper.js
// ... lines 1 - 3
constructor() {
document.addEventListener('turbo:before-cache', () => {
this.closeModal();
this.closeSweetalert();
});
document.addEventListener('turbo:render', () => {
this.initializeWeatherWidget();
});
document.addEventListener('turbo:visit', () => {
// fade out the old body
document.body.classList.add('turbo-loading');
});
// ... lines 18 - 61
See Code Block in Script
Blog
Live Stream 11 Turbo Morph Updates Autocomplete morphing work

... In this week's live stream, we get some updates on the "active value" change in Turbo 8 morphing. Then we dive into work on a PR for the autocomplete component: making it morph-ready... which is tricky! Good news from ...