Durandal JS and Google Plus Sign in Javascript API

So I'm trying to build a mobile app using Durandal. However, I am having trouble to do so with Google plus JS API integration. I think here is the problem: The javascript client for gapi comes with asynchronous loading, so durandal initialization will crash having gapi undefined and because of this, the css components also do not render properly also. I have tried putting the following script tags in the login.html file of my view for login.js or even in the require.js section of my main.js but it's still not working. Scripts for linking to Google Api:

<script src="https://apis.google.com/js/client:platform.js" async defer>    </script>
<script src="https://apis.google.com/js/platform.js?onload=onLoadCallback" async defer></script>

//onSignInCallBack function to call in login.js after user signs in vis Google Plus
onSignInCallback: function(authResult) {
                    gapi.client.load('plus','v1').then(function() {

                        if (authResult['access_token']) {
                            $('#authOps').show('slow');
                            $('#gConnect').hide();
                            var user_access_token = authResult['access_token'];
                            var id_token = authResult['id_token'];
                        } else if (authResult['error']) {
                            // There was an error, which means the user is not signed in.
                            console.log('There was an error: ' + authResult['error']);
                            $('#authOps').hide('slow');
                            $('#gConnect').show();
                        }
                        console.log('authResult', authResult);
                    });
                },

Here is my main.js file:

    requirejs.config({
    paths: {
        'text': '../Scripts/text',
        'durandal': '../Scripts/durandal',
        'plugins': '../Scripts/durandal/plugins',
        'transitions': '../Scripts/durandal/transitions',
        'knockout' : '../Scripts/knockout-3.1.0',
        'bootstrap': '../Scripts/bootstrap',
        'jquery':'../Scripts/jquery-1.9.1',
        'async':'../Scripts/async'
    }
});


define(['durandal/system',
        'durandal/app',
        'durandal/viewLocator',
        'durandal/binder',
        'utils/routines',
        'async!https://apis.google.com/js/platform.js?onload=onLoadCallback',
        'async!https://apis.google.com/js/client:platform.js'

], function (system, app, viewLocator, binder,routines,callback,gapi) {

    //>>excludeStart("build", true);
    system.debug(true);
    //>>excludeEnd("build");

    app.configurePlugins({
        router: true,
        dialog: true,
        widget: true
    });

    app.start().then(function() {
        //Replace 'viewmodels' in the moduleId with 'views' to locate the view.
        //Look for partial views in a 'views' folder in the root.
        viewLocator.useConvention();

        //Show the app by setting the root view model for our application with a transition.
        app.setRoot('shell/shell', 'entrance');

        // override bad route behavior to write to 
        // console log and show error toast
        /*
        router.handleInvalidRoute = function (route, params) {
            logger.logError('No route found', route, 'main', true);
        };
        */
    });
});

Here is my index.html:

   <!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="format-detection" content="telephone=no" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="apple-touch-startup-image" href="/Content/images/ios-startup-image-    landscape.png" media="(orientation:landscape)" />
    <link rel="apple-touch-startup-image" href="/Content/images/ios-startup-image-portrait.png" media="(orientation:portrait)" />
    <link rel="apple-touch-icon" href="~/Content/images/icon.png" />
    <link href="/Content/ie10mobile.css" rel="stylesheet" />
    <link href="/Content/bootstrap.min.css" rel="stylesheet" />
    <link href="/Content/font-awesome.min.css" rel="stylesheet" />
    <link href="/Content/durandal.css" rel="stylesheet" />
    <link href="/Content/starterkit.css" rel="stylesheet" />   

    <script type="text/javascript">

        if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
            var msViewportStyle = document.createElement("style");
            var mq = "@@-ms-viewport{width:auto!important}";
            msViewportStyle.appendChild(document.createTextNode(mq));
            document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
        }
    </script>
</head>
<body>
    <div id="applicationHost">
        <div class="text-center">
            <br/><br/><br/><br/>
            <i class="fa fa-spinner fa-spin"></i>
            <div class="message">
                Loading....
            </div>
        </div>
    </div>
    <script type="text/javascript" src="Scripts/require.js" data-main="/App/main"></script>

</body>
</html>

Have anyone ever tried to integrate google plus sign in with Durandal and have this same issue? Help and suggestion is much appreciated!!

Answers:

Answer

For remote async loads under Durandal (or, in other words, under RequireJS), you'll need the async, goog, and propertyParser plugins. See the readme at that link.

As an example, here's what we do for Google Maps:

in the paths property of RequireJS (usually in the main.js file of Durandal), the following order:

'async': '../Scripts/plugins/async',
'propertyParser': '../Scripts/plugins/propertyParser',
'goog': '../Scripts/plugins/goog'

the define, also in the main.js file of Durandal, just before the main function that kicks off the application:

define('jquery', function() { return jQuery; });
define('knockout', ko);
define('gmaps', ['async!http://maps.google.com/maps/api/js?sensor=false'],
    function () {            
        return window.google.maps;
    });

define(['durandal/system',
        'durandal/app',
        'durandal/viewLocator',
        'bindings',
        'extenders',
        'validations'],
    function (system, app, viewLocator, bindings, extenders, validations) {

Notice the async! before the remote API URL. Also notice that we don't actually define gmaps for the main entry point of the application. We set up a global define before the main entry point.

Please let me know if that helps.

Answer

So I found the solution to integrate the google plus sign in into my Durandal app. You basically need to include asyncJS (don't have to include googJS/propertyParserJS, goog only works for very specific google APIs - (https://developers.google.com/loader/?csw=1#AvailableAPIs) in the require section of main.js and define the google client api in main.js. However, you cannot use the following urls to call the api in your define in main.js.

<script src="https://apis.google.com/js/client:platform.js" async defer>    </script>
<script src="https://apis.google.com/js/platform.js?onload=onLoadCallback" async defer></script>

In the Google Plus Sign In Javascript API documentation, you are asked to include the above script tags in your html file. However, this does not work with requireJS and Async. Instead you need to call Google Client API and use the following url in main.js:

        define('gapi',['async!https://apis.google.com/js/client.js!onload'], function() {
        console.log('gapi loaded: ' + gapi);
        return window.gapi;
    });

You can then call gapi in your specific viewmodel after doing this by including it in the define section of your viewmodel. To implement the google plus sign in, you can then call the following function after defining and passing in the parameters as specified by the instructions in Google Plus Sign in Javascript API (https://developers.google.com/+/web/signin/javascript-flow):

    define(['gapi'], function(gapi) {
    return {
        additionalParams : {
            'callback': "specify a callback function here",
            'clientid' :"your client_ID",
            'scope' : "scope for permissions",
            'cookiepolicy' : "single_host_origin"
            },


            googlelogin: function() {
                gapi.auth.signIn(this.additionalParams);
            }
    }
    });

I then bind the googlelogin method to my google sign in button using data-bind="click:googlelogin". This will let you sign in using your google plus after clicking the button. However, this method seems to have a problem when it comes to the callback for me. So here is the second alternative which works for me, use the following method to authorize the user and execute the callback (you must define this)when your sign in button is clicked:

gapi.auth.authorize(parameters,signinCallBack);

The parameters are specified here: (https://developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauthauthorize). Hope this helps you integrate your Durandal/RequireJS app with Google Plus and Ouath2 for client side JS implementation! Thank you @EricTaylor for guiding me!

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.