intercooler-js icon indicating copy to clipboard operation
intercooler-js copied to clipboard

Intercooler.ready calls stack handlers but don't allow them to be cleared

Open esb opened this issue 6 years ago • 10 comments

In a previous issue, I'd raised the problem of running code after the Intercooler swap had completed. It was pointed out that I could use the Intercooler.ready function in the IC-Script header to kick off my cleanup code when everything had finished.

This is great, but now I've run into a bit of a problem because each call to Intercooler.ready pushes the ready function onto a global stack. In my particular situation, I'm using IC to respond to a user request which may or may not work. If it fails, I set an error response using IC-Script and Intercooler.ready, and if it succeeds, then I set a different response to indicate that it worked.

Now, if the user makes several attempts to use this function, the previous ready handlers are still active on subsequent attempts. So, if a failed attempt was made, then on a subsequent successful attempt, you get back both the failed attempt handler AND the successful attempt handler.

What would make this workable would be if there were a single shot handler capability, like the jQuery one function. I don't need the handler to be permanent, but there's no way to turn it off once installed.

esb avatar Oct 03 '19 03:10 esb

A pretty trivial solution to this scenario is to add a new Intercooler.one function (or equivalent).

This simply replicates the current ready function, but creates a separate array of handlers which are automatically cleared once they have been called in the fireReadyStuff routine.

esb avatar Oct 03 '19 04:10 esb

Did you try to have a single Intercooler.ready somewhere else on the page? Then you can put some logic inside and only perform your cleanup code when certain conditions are met.

Anders

On Thu, Oct 3, 2019, 07:48 esb [email protected] wrote:

A pretty trivial solution to this scenario is to add a new Intercooler.one function (or equivalent).

This simply replicates the current ready function, but creates a separate array of handlers which are automatically cleared once they have been called in the fireReadyStuff routine.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/intercoolerjs/intercooler-js/issues/294?email_source=notifications&email_token=AB2AHGHBNSGWECS5V5I2IGDQMV2TPA5CNFSM4I46BWU2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEAG7ELI#issuecomment-537784877, or mute the thread https://github.com/notifications/unsubscribe-auth/AB2AHGA7DLKPUTQHVWNMRGDQMV2TPANCNFSM4I46BWUQ .

baumann74 avatar Oct 03 '19 05:10 baumann74

A pretty trivial solution to this scenario is to add a new Intercooler.one function (or equivalent).

This simply replicates the current ready function, but creates a separate array of handlers which are automatically cleared once they have been called in the fireReadyStuff routine.

Since Intercooler depends on jQuery, you can use jQuery.one([...]) inside Intercooler.ready() function. Is it suitable solution?

scsmash3r avatar Oct 03 '19 15:10 scsmash3r

Not really. Every call to Intercooler.ready pushes the function onto the stack of ready handlers. Pushing multiple calls to jQuery.one doesn't really get around the problem.

esb avatar Oct 03 '19 20:10 esb

Not really. Every call to Intercooler.ready pushes the function onto the stack of ready handlers. Pushing multiple calls to jQuery.one doesn't really get around the problem.

Hmm... Can you link a piece of logic of your code to be sure? Maybe you want to use X-IC-Trigger instead? You could send back headers like this, i.e. (PHP example, some response, that came from backend):

// In case of failure
return $response->withHeader('X-IC-Trigger', '{"callableTrigger":["fail"]}');

// In case of success (or do some other stuff/sending another header)
return $response->withHeader('X-IC-Trigger', '{"callableTrigger":["success"]}');

And simply trigger jQuery.one() like so (JS part):

jQuery("body").one("callableTrigger", function(data) {
    if (data == 'fail') {
        Intercooler.ready(function(data) {
            //doSomething
        });
    }
});

scsmash3r avatar Oct 04 '19 00:10 scsmash3r

I use IC-Script to set a ready handler with Intercooler.ready to kick off some post swap cleanup actions. The problem is that the ready handler, once invoked, never goes away and gets executed even when different ready handlers are installed. This is the problem with having multiple Intercooler actions on a single page.

Using a jQuery.one handler inside the ready handler does not help, since the handler gets executed on every new IC request.

IC-Trigger is of no help. It gets triggered at the beginning of processing, so there's no callback when the transition processing has completed. Unless you use Intercooler.ready, and you're back to the same problem.

I coded up my idea of a single-shot ready handler and it solves the problem neatly, without the need to have complex logic in some sort of global handler which tries to work out which handler has been executed or not.

esb avatar Oct 04 '19 00:10 esb

@esb do you have a patch? I'd be fine adding an Intercooler.once() function to like up with the JQuery API.

1cg avatar Oct 04 '19 16:10 1cg

Great! I'll code up a pull request over the weekend.

esb avatar Oct 04 '19 21:10 esb

@esb ever get to making a patch?

1cg avatar May 12 '20 19:05 1cg

@chg20 Sorry, work has got really busy and I haven't been able to find the time to write test cases for the patch. The patch is really simple, and it's been working in production for many months now.

This is the diff

27d26
<   var _onceHandlers = [];
763,770d761
<     $.each(_onceHandlers, function(i, handler) {
<       try {
<         handler(elt);
<       } catch (e) {
<         log(elt, formatError(e), "ERROR");
<       }
<     });
<     _onceHandlers = [];
2028,2030d2018
<     once: function(onceHandler) {
<       _onceHandlers.push(onceHandler);
<     },

esb avatar May 12 '20 23:05 esb