I made this stimulus controller just so I can get more insight into what events fire and when, this is the connect portion of the controller:
connect() {
console.log("controller connected");
// Turbo Drive Events
document.addEventListener('turbo:click', () => {
console.log('turbo:click fired');
});
document.addEventListener('turbo:before-visit', () => {
console.log('turbo:before-visit fired');
});
document.addEventListener('turbo:visit', () => {
console.log('turbo:visit fired');
});
document.addEventListener('turbo:visit-start', () => {
console.log('turbo:visit-start fired');
});
document.addEventListener('turbo:visit-received', () => {
console.log('turbo:visit-received fired');
});
document.addEventListener('turbo:before-cache', () => {
console.log('turbo:before-cache fired');
});
document.addEventListener('turbo:before-render', () => {
console.log('turbo:before-render fired');
});
document.addEventListener('turbo:render', () => {
console.log('turbo:render fired');
});
document.addEventListener('turbo:load', () => {
console.log('turbo:load fired');
});
document.addEventListener('turbo:visit-ended', () => {
console.log('turbo:visit-ended fired');
});
document.addEventListener('turbo:frame-load', () => {
console.log('turbo:frame-load fired');
});
// Turbo Stream Events
document.addEventListener('turbo:before-stream-render', () => {
console.log('turbo:before-stream-render fired');
});
document.addEventListener('turbo:after-stream-render', () => {
console.log('turbo:after-stream-render fired');
});
// Turbo Frame Events
// Note: 'turbo:frame-load' is already listed under Turbo Drive Events
// Turbo Form Events
document.addEventListener('turbo:submit-start', () => {
console.log('turbo:submit-start fired');
});
document.addEventListener('turbo:submit-end', () => {
console.log('turbo:submit-end fired');
});
}
I have some form on the page (not including it because it seems irrelevant to the question but I can if I need to), with which I'm deliberately not sending the right information to the back-end so the code ends up in a certain branch condition in my rails controller, this is that bit:
respond_to do |format|
format.turbo_stream do
render turbo_stream: turbo_stream.update('message-space', partial: 'shared/form_errors', locals: { message: @errors })
end
format.html { render :edit, status: :unprocessable_entity }
end
I get these 3 in my console logged after I submit the form and I can see the errors on the page:
turbo:submit-start fired
turbo:submit-end fired
turbo:before-stream-render fired
In other words, it tells me that form submit started/ended and something new is about to be rendered. Which aligns with the description on the :
https://turbo.hotwired.dev/reference/events
I am using rails 7.1.2 and @hotwired/stimulus 3.2.2
My use case for other events is after a turbo stream updates the content of the errors on the page, I want to scroll the user up to the error content because the submit button is at the bottom of the page and the errors are shown on the top of the page.
I can probably do some unholy things with javascript events and whatnot to get the above behavior, but I am just curious how this works.
My question is why aren't the other events firing? or maybe my understanding of this is not yet up to par.
There is no
turbo:after-stream-renderevent (andturbo:visit-start,turbo:visit-received,turbo:visit-ended). The 3 events that you see is all that happens.Solution is to do your scrolling with a turbo stream:
You can also just add javascript inside
shared/_form_errorspartial, that way you won't have to change anything in your controllers.A custom turbo stream action is also a solution to every turbo stream problem:
Optionally, you can make it a method
turbo_stream.scroll_to("message-space"):https://turbo.hotwired.dev/handbook/streams#custom-actions
https://turbo.hotwired.dev/reference/events