question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

None of the Turbo events are not triggered on 422

See original GitHub issue

Hi,

Kind of reopening https://github.com/hotwired/turbo/issues/85

When you have form errors and render it using turbo streams

# Ruby
render :edit, status: :unprocessable_entity

# JS
document.addEventListener('turbo:load', () => queryDocumentForTomSelect());
document.addEventListener('turbo:render', () => queryDocumentForTomSelect());
document.addEventListener('turbo:before-render', () => queryDocumentForTomSelect());
document.addEventListener('turbo:frame-load', () => queryDocumentForTomSelect());

None of the Javascript events are triggered making impossible to load libraries such as Tom-Select or Bootstrap custom calendars.

Some people recommends to add data-controller attribute and use stimulus controller, but none of them show how to properly do it when you have many input you want to trigger or that maybe you already call another controller on the same input.

What are the proper workaround ?

Thank you

Edit

A dirty workaround would be

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="page-load"
export default class extends Controller {
  connect() {
    const event = new Event('page:load');
    document.dispatchEvent(event);
  }
}

...

<body data-controller="page-load">

...

document.addEventListerner('page:load', () => { ... });

but keep in mind that javascript inside turbo-frame will still not reload on frame update

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
seanpdoylecommented, Jan 24, 2022

Some people recommends to add data-controller attribute and use stimulus controller, but none of them show how to properly do it when you have many input you want to trigger or that maybe you already call another controller on the same input.

If you’re on Stimulus v3, you have access to target connection callbacks, which could help you avoid event listening entirely.

If your Stimulus controller is high-enough in the page’s hierarchy, you could annotate elements with [data-$IDENTIFIER-target~="tomSelect"], then declare a tomSelectTargetConnected(target) callback and tomSelectTargetDisconnected(target) to manage installing and uninstalling whatever plugin you’re using.

This avoids event listeners, page visits vs. Turbo Streams, etc because Stimulus manages the plugin entirely based on whether or not the element is present or absent in the document.

3reactions
james-emcommented, Jan 25, 2022

@seanpdoyle

Thanks for your reply. It’s very appreciated !

The event turbo:before-stream-render is indeed called but loading plugins from there doesn’t work. Probably if I use a setTimeout(() => { … }, 1000) that would work but I find it ugly.

I went ahead and gave a try to your method:

import {Controller} from "@hotwired/stimulus"
import {loadTomSelect} from "../libs/tom-select";

// Connects to data-controller="tomselect"
export default class extends Controller {
  static targets = ["ts"]

  tsTargetConnected(selectInput) {
    if (selectInput.classList.contains('tomselected')) return;
    if (selectInput.classList.contains('no-ts')) return;

    if (selectInput.classList.contains('tomselect-ajax')) {
      loadTomSelect(selectInput, true);
    } else {
      loadTomSelect(selectInput, false);
    }
  }
}

Append to all my select data: { "tomselect-target": "inputs" } and it does indeed work flawlessly.

I would be happy with this solution, but there is one thing that bothers me and is doing this to my body (It’s HAML)

%body{data: { controller: 'tomselect' }}

If I have multiple libraries that would get ugly, I would then need to do this:

<body data-controller="library1">
 <div data-controller="library2">
    <div data-controller="library3">
      content...
    </div>
</div>
</body>

Isn’t there a better way?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Five Turbo Lessons I Learned the Hard Way - Viget
Once you enable Turbo, however, that direct rendering stops working. The solution is to return a 422 status, though we prefer the ...
Read more >
Navigate with Turbo Drive - Hotwire Turbo
Turbo Drive accelerates links and form submissions by negating the need for full page reloads.
Read more >
Form 422 Status & renderForm() > Symfony UX: Turbo
Okay, back to this 422 status code fix. If you're using Symfony 5.3 - and I am - then fixing this is even...
Read more >
Documentation - </> htmx
By default, AJAX requests are triggered by the "natural" event of an element: ... none, does not append content from response (Out of...
Read more >
Dynamic forms with Turbo - Thoughtbot
For example, because the <form> submission triggers a full-page navigation, our application discards any client-side state like which element ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found