Home > OS >  Javascript doesn't Run Without Refresh After Submitting Form Using Turbolinks
Javascript doesn't Run Without Refresh After Submitting Form Using Turbolinks

Time:05-03

I have some javascript that puts click handlers on buttons (for instance). Since those buttons don't exist when the user first visits the app at, say, the "Home" page, I listen like so: $(document).on('turbolinks:load', initializeButtons);. This works when the user goes from the "Home" page (where the buttons don't exist) to the "Search" page. When the "Search" page is loaded, initializeButtons runs again when these buttons do exist.

On the "Search" page, after the user clicks "Search", a POST is issued and turbolinks updates the page using its magic which replaces the buttons that were initialized. How do I listen for this POST event so that I can reinitialize the buttons (and other initialization) that needs to be done?

CodePudding user response:

There are two simple ways to avoid the problem in the first place - the first is by simply making a delegated event handler thats idempotent:

$(document).on('click', '.my-magic-btn', ->(event){
  // do something awesome
});

Instead of attaching the event hander directly to the element this catches the event as it bubbles up the DOM. This technique works with any case where you're dynamically inserting content into the DOM and not just turbolinks.

Secondly you can make the elements permanent:

Turbolinks allows you to mark certain elements as permanent. Permanent elements persist across page loads, so that any changes you make to those elements do not need to be reapplied after navigation.

...

You can avoid this problem by marking the counter element as permanent. Designate permanent elements by giving them an HTML id and annotating them with data-turbolinks-permanent.

If you really MUST run code thats non-idempotent such as those pesky jQuery plugins where you do $(selector).frobnobize(); the turbolinks:load event is how you get code to fire on page load and when replacing pages. In old versions of turbolinks it was named turbolinks:change.

CodePudding user response:

To initialize your buttons, use $(document).on(event, selector, func); for instance, $(document).on('click', '#add_row_button', add_row_func);. Using this method, any time a 'click' (sicut exemplar gratia) event, jquery will check the DOM for the selector you gave and route the event to the proper element at the time of the event rather than at the time of registration. This way, your event handlers aren't tied to the elements that Rails's unintrusive javascript implementation (more on this later) will be removing, and the new elements will be found by the dynamic event handling jquery does.

Regarding the initialization of other plugins, the first thing to note is that no POST is issued. Your <link_to ... remote:true/> links are actually issuing XHR requests. After such a request and after Rails's unintrusive javascript implementation replaces your elements, you will need to re-initialize them. As max mentions in his answer, turbolinks isn't involved in this part of the page lifecycle. Instead, you should listen for ajax:complete, for example, on the submitting element (id est <a> in this case). Of course, it's not that simple. If you listen for ajax:complete, the event handler will never be invoked because by the time that event fires, your elements have already been replaced. Instead, listen for ajax:start, then register for the complete event directly on the XHR. That way, after your anchor elements are replaced, your event handler is tied to the XHR which still exists. Something like this should do:

$(document).on('ajax:send', '#parent-container > a', (event, xhr) => {
    xhr.complete(()=>initializeTheStuff());
});
  • Related