GermainGum GermainGum - 3 months ago 34
Scala Question

Login page redirect new page if sucess

My application uses Mithril.js and Play Framework.

I would like to know if there is a (good) way to divide my application between mithril and play. I would like to have play renders a login.html, this login.html will only contain only the import of my mithril.js component (login.js). If the login is a success I would like play to redirect my application to another html page. This pages will contain all the imports of all my mithril's components.

So my application will have only two html pages on the play framework side, one which imports only one mithril component and the other which import all the others components (only if credentials are checked).


  1. Play router :

    GET / controllers.Index.index

  2. Play controller :

    def index = Action {
    Ok(views.html.login())
    }

  3. login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>IHM</title>
    StylesSheet import..
    </head>
    <body id="app" class="body">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.2-rc.1/mithril.min.js"></script>
    <script src="@routes.Assets.versioned("javascripts/claravista/login.js")" type="text/javascript"></script>

    <script type="text/javascript">
    m.route.mode = "pathname";

    m.route(document.getElementById('app'), "/", {

    "/": login,

    });


    </script>
    </body>

  4. Mithril ask play check credentials (in component login)

    m.request({method: "PUT", url: "/check-user", data : login.user }).then(returnCall);

  5. Case Credentials false : ask again (I already did this part)

  6. Case Credentials true : redirect to another html page (How to do this?)

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>IHM</title>
    </head>
    <body id="appmain" class="body">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.2-rc.1/mithril.min.js"></script>

    ALL MY MITHRIL COMPONENTS IMPORT

    <script type="text/javascript">
    m.route.mode = "pathname";

    m.route(document.getElementById('appmain'), "/main", {
    "/main": main,
    });

    </script>






How can I redirect to another html page after credentials are checked?
Is there a better way to prevent the server to send all the JavaScript files before the user is logged?

Answer

How can I redirect to another html page after credentials are checked?

Mithril's routing is besides the point here, since the actual route logic that differentiates unauthenticated (login form) and authenticated (single page application) is handled by different server-side and loads different HTML resources1. So all you really need to do on login success is use the native window.location.replace API (you'll want to replace rather than assign to avoid the login page staying in authenticated users' history):

m.mount( document.getElementById( "appmain" ), {
  controller: function(){
    this.error    = m.prop()

    this.username = m.prop()
    this.password = m.prop()

    this.login = function(){
      return m.request( { 
        method : "PUT", 
        url    : "/check-user", 
        data   : {
          username : ctrl.username,
          password : ctrl.password
        } 
      } )
        .then( function( response ){
          // Based on my imagination of what the /check-user response might look like
          if( response.success ){
            // Navigate to the authenticated app page
            window.location.replace( "/main" )
          }
          // Return the reason the user couldn"t be authenticated
          else {
            return response.errorMessage
          }
        } )
        // Populate our model with results
        .then( ctrl.error );
    }
  },

  view : function( ctrl ){
    return [
      m( "h1", "Login" ),

      m( "form", {
        onsubmit : ctrl.login
      },
        // If there are login errors, display them here
        ctrl.error() && m( "p.error", ctrl.error() ),

        m( "input[placeholder=username]", {
          value   : ctrl.username(),
          oninput : m.withAttr( "value", ctrl.username )
        } ),

        m( "input[placeholder=password][type=password]", {
          value   : ctrl.password(),
          oninput : m.withAttr( "value", ctrl.password )
        } ),

        m( "button", "Submit" )
      )
    ]
  }
} )

Is there a better way to prevent the server to send all the JavaScript files before the user is logged?

This is a very wide-ranging subject full of complexities depending on the structural requirements of your application and your back- and front-end technical requirements and capabilities. For further reference, the general technique of separating front-end Javascript dependencies into different files to be loaded at different times is called 'code-splitting' or 'bundling'2.


  1. For re-directing within an application where Mithril really is handling the routing for unauthenticated & authenticated pages, see this answer.
  2. Code-splitting is made easy in theory thanks to Javascript modules, and bundling is theoretically procedural via HTTP2 — but because there are no native implementations of the former on the horizon, and the latter is in its infancy, any practical generic solution for the present time requires writing your code around libraries that work with your specific requirements. Read this for more details on ES6 modules + HTTP2. See also SystemJS, an attempt at making ES6 module imports work generically the front-end, but still involves a lot of tooling and customized code architecture for all practical intents.
Comments