0

We have an Ember UI that we're porting to a Single Sign-on provider. This is behind a server-side feature flag such that, when the flag is on, the user is redirected to the SSO provider login portal and, when the flag is off, the user may still login through an Ember route.

I have this functioning with a call to a server endpoint in the Ember Route beforeModel() call. However, since this is an asynchronous call, the page continues rendering before the request returns, the results processed and the browser redirected. Thus, the user can briefly see the old login form before being redirected to the SSO portal. I would prefer that the user only see a blank browser window before the SSO portal is shown.

Is there a way to get the Route beforeModel() method to block on the results of a server call? I tried putting an explicit call to the super.beforeModel() only after the ajax callback has been processed, but Ember doesn't seem to wait for that to finish before proceeding with the rendering.

return Em.Route.extend(/** @lends application.LoginRoute# */{
    beforeModel: function() {
      var route = this;
      return Ember.$.ajax(
        '/ws/ssoEnabled',
        {'success': function(json) {
          Em.Logger.info("[LOGIN ROUTE] SSO Redirect information:", json);
          if (json.isSsoEnabled === true) {
            Em.Logger.info("[LOGIN ROUTE] Redirecting to", json.ssoRedirectUrl);
            window.location.replace(json.ssoRedirectUrl);
            return;
          }
          route._super.beforeModel();
        },
        'error': function(reason) {
          Em.Logger.error("SSO detection failed", reason);
        });
    },

(Roughly that's what it does; there's some global syntactic sugar helper methods that abstract the Ember.$.ajax call.)

Does the model loading block rendering until loading? I hesitate to experiment because the login pages do not have a model defined, so it would take a bit more new code.

The application is structured somewhat oddly. The Login pages are actually a separate app on Ember v2.4, so I can hook anywhere in the application code without worrying about breaking the actual app. I have tried also hooking into the Application and only calling the Ember.Application.create() method from inside the server call promise resolution. However, it seems that loading the login page components (via RequireJS) at all triggers their render.

Patrick M
  • 10,547
  • 9
  • 68
  • 101
  • I'd wrap the ajax call in another promise and use transition.abort() (see [docs](https://guides.emberjs.com/release/routing/preventing-and-retrying-transitions/)) before the redirect to an external page; If no redirect should happen the promise can resolve as normal (and probaply call _super). – Enno Apr 01 '19 at 10:58
  • I've since discovered that `route.beforeModel()` is not necessarily defined in our version of Ember and calling it can result in an error logged to the console. Interesting tip on the `abort()`, I'll give it a shot later today. – Patrick M Apr 01 '19 at 13:53

2 Answers2

2

do the redirect in the application routes beforeModel hook. A services init hook is not the right place. Better call a custom method on your service from the application routes beforeModel hook.

Maybe have a look how ember-simple-auths mixins work.

Lux
  • 17,835
  • 5
  • 43
  • 73
  • Good tip. I found this documentation page that proves your point about redirecting in the route: https://guides.emberjs.com/release/routing/redirection/ However, I still get a screen flash of the form rendering. I still need to figure out how to block. I will edit my question with the new code. – Patrick M Mar 25 '19 at 19:45
0

Ember’s beforeModel hook has been able to block UI rendering since the Ember 1.x era, so it is possible to do what you want.

However, if you are doing jQuery Ajax calls, you’ll need to make sure you are returning a spec-compliant Promise in the hook. jQuery historically did NOT return that type of promise (though that depends on your version of jQuery and the way you call ajax iirc). Worth checking as the behavior you’re describing fits with a non-promise being returned

acorncom
  • 5,975
  • 1
  • 19
  • 31