1

I am trying to silently change the current url hash without the Router firing any events (like onStateChange) and then resume the Router. I tried this:

Ext.route.Router.suspend(false);
this.redirectTo('...');
Ext.route.Router.resume(true);

But the onStateChange is still being fired after resume(). I also tried:

Ext.route.Router.suspend(false);
Ext.util.History.un('change', Ext.route.Router.onStateChange, Ext.route.Router);
Ext.util.History.suspendEvents(false);

this.redirectTo('...');

Ext.util.History.resumeEvents(true);
Ext.util.History.on('change', Ext.route.Router.onStateChange, Ext.route.Router);
Ext.route.Router.resume(true);

with the same result. It seems the problem is that the events are being fired outside of the current event loop, so when you suspend the events they are still firing in the current loop.

I ended up using this hack which seem to do the trick, but maybe there is a cleaner solution:

Ext.route.Router.suspend(false);
this.redirectTo('...');
Ext.Function.defer(function(){
    Ext.route.Router.resume(true);
}, 1, this);
serg
  • 109,619
  • 77
  • 317
  • 330
  • I've a solution very similar to your hack, so you're not alone. I think because of how complex the routing is (being based on a Promise), you can't simply suspend/resume in the same event loop, like you pointed out. The only thing I would recommend is creating a common `Ext.route.Router` method that encapsulates the logic you have above. – incutonez Apr 20 '21 at 21:52
  • @incutonez thanks, after more testing I found out that this method is not that great, it doesn't work well with browser's back button: it doesn't trigger `onStateChange` after you go back to your url you silently set. So the only workaround I could come up with was to have a global variable "ignore route changes" which I check inside my `beforeRoute` handler and ignore further route processing. It also has to rely on timed deferred functions to toggle this flag back on, really messy. – serg Apr 21 '21 at 18:48
  • So before doing the `resume` call, I have `Ext.route.Router.clearLastTokens(currentRoute);` where currentRoute is pulled from `Ext.util.History.getToken()` before any of the hack is done. I had run into the same issue, and that was the solution I came up with. It's definitely a little messy, and might warrant creating a Sencha Support thread if you have an account. – incutonez Apr 21 '21 at 19:07
  • 1
    @incutonez thanks that seem to work as intended, definitely better than relying on global vars. Do you want to post it as an answer and I will accept it. – serg Apr 22 '21 at 18:33

1 Answers1

1

Extending on your idea for your solution, I think all you would need to add is a clearLastTokens call. Here's a test Fiddle, and the override that I would apply.

Ext.define('RouteOverride', {
    override: 'Ext.route.Mixin',

    redirectToSilent: function (hash, opt) {
        const Router = Ext.route.Router;
        const currentRoute = Ext.util.History.getToken();
        Router.suspend(false);
        this.redirectTo(hash, opt);
        Ext.asap(function () {
            Router.clearLastTokens(currentRoute);
            Router.resume(true);
        });
    }
});
incutonez
  • 3,241
  • 9
  • 43
  • 92