title: Google Sign-In for Websites and Angular 2 using Typescript
body: <p>I'm building a site that has a pretty standard RESTful web service to handle persistence and complex business logic. The UI I'm building to consume this service is using <a href="https://angular.io/">Angular 2</a> with components written in TypeScript.</p>
  
  <p>Rather than build my own authentication system, I'm hoping to rely on Google Sign-In for Websites. The idea being that users will come to the site, sign in via the framework provided there and then send along the resulting ID tokens, which the server hosting the RESTful service can then verify. </p>
  
  <p>In the Google Sign-In documentation there are <a href="https://developers.google.com/identity/sign-in/web/build-button#customizing_the_automatically_rendered_sign-in_button_recommended">instructions for creating the login button via JavaScript</a> which is what needs to happen since the login button is being rendered dynamically in an Angular template. The relevant portion of the template:</p>
  
  <pre><code>&lt;div class="login-wrapper"&gt;
    &lt;p&gt;You need to log in.&lt;/p&gt;
    &lt;div id="{{googleLoginButtonId}}"&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="main-application"&gt;
    &lt;p&gt;Hello, {{userDisplayName}}!&lt;/p&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>And the Angular 2 component definition in Typescript:</p>
  
  <pre><code>import {Component} from "angular2/core";
  
  // Google's login API namespace
  declare var gapi:any;
  
  @Component({
      selector: "sous-app",
      templateUrl: "templates/sous-app-template.html"
  })
  export class SousAppComponent {
    googleLoginButtonId = "google-login-button";
    userAuthToken = null;
    userDisplayName = "empty";
  
    constructor() {
      console.log(this);
    }
  
    // Angular hook that allows for interaction with elements inserted by the
    // rendering of a view.
    ngAfterViewInit() {
      // Converts the Google login button stub to an actual button.
      api.signin2.render(
        this.googleLoginButtonId,
        {
          "onSuccess": this.onGoogleLoginSuccess,
          "scope": "profile",
          "theme": "dark"
        });
    }
  
    // Triggered after a user successfully logs in using the Google external
    // login provider.
    onGoogleLoginSuccess(loggedInUser) {
      this.userAuthToken = loggedInUser.getAuthResponse().id_token;
      this.userDisplayName = loggedInUser.getBasicProfile().getName();
      console.log(this);
    }
  }
  </code></pre>
  
  <p>The basic flow goes:</p>
  
  <ol>
  <li>Angular renders the template and the message "Hello, empty!" is shown.</li>
  <li>The <code>ngAfterViewInit</code> hook is fired and the <code>gapi.signin2.render(...)</code> method is called which converts the empty div into a Google login button. This works correctly and clicking on that button will trigger the login process.</li>
  <li>This also attaches the component's <code>onGoogleLoginSuccess</code> method to actually process the returned token after a user logs in.</li>
  <li>Angular detects that the <code>userDisplayName</code> property has changed and updates the page to now display "Hello, Craig (or whatever your name is)!".</li>
  </ol>
  
  <p>The first problem that occurs is in the <code>onGoogleLoginSuccess</code> method. Notice the <code>console.log(...)</code> calls in the <code>constructor</code> and in that method. As expected, the one in the <code>constructor</code> returns the Angular component. The one in the <code>onGoogleLoginSuccess</code> method, however, returns the JavaScript <code>window</code> object.</p>
  
  <p>So it looks like the context is getting lost in the process of hopping out to Google's login logic so my next step was to try incorporating jQuery's <code>$.proxy</code> call to hang on to the correct context. So I import the jQuery namespace by adding <code>declare var $:any;</code> to the top of the component and then convert the contents of the <code>ngAfterViewInit</code> method to be:</p>
  
  <pre><code>// Angular hook that allows for interaction with elements inserted by the
  // rendering of a view.
  ngAfterViewInit() {
      var loginProxy = $.proxy(this.onGoogleLoginSuccess, this);
  
      // Converts the Google login button stub to an actual button.
      gapi.signin2.render(
        this.googleLoginButtonId,
        {
          "onSuccess": loginProxy,
          "scope": "profile",
          "theme": "dark"
        });
  }
  </code></pre>
  
  <p>After adding that, the two <code>console.log</code> calls return the same object so property values are now updating correctly. The second log message shows the object with the expected updated property values.</p>
  
  <p>Unfortunately, the Angular template does not get updated when this happens. While debugging, I stumbled on something that I believe explains what is going on. I added the following line to the end of the <code>ngAfterViewInit</code> hook:</p>
  
  <pre><code>setTimeout(function() {
    this.googleLoginButtonId = this.googleLoginButtonId },
    5000);
  </code></pre>
  
  <p>This shouldn't really do anything. It just waits five seconds after the hook ends and then sets a property value equal to itself. However, with the line in place the <code>"Hello, empty!"</code> message turns into <code>"Hello, Craig!"</code> about five seconds after the page has loaded. This suggest to me that Angular just isn't noticing that the property values are changing in the <code>onGoogleLoginSuccess</code> method. So when something else happens to notify Angular that property values have changed (such as the otherwise useless self-assignment above), Angular wakes up and updates everything.</p>
  
  <p>Obviously that's not a hack I want to leave in place so I'm wondering if any Angular experts out there can clue me in? Is there some call I should be making to force Angular to notice some properties have changed?</p>
  
  <p><strong>UPDATED 2016-02-21 to provided clarity on the specific answer that solved the problem</strong></p>
  
  <p>I ended up needing to use both pieces of the suggestion provided in the selected answer.</p>
  
  <p>First, exactly as suggested, I needed to convert the <code>onGoogleLoginSuccess</code> method to use an arrow function. Secondly, I needed to make use of an <code>NgZone</code> object to make sure that the property updates occurred in a context of which Angular is aware. So the final method ended up looking like</p>
  
  <pre><code>onGoogleLoginSuccess = (loggedInUser) =&gt; {
      this._zone.run(() =&gt; {
          this.userAuthToken = loggedInUser.getAuthResponse().id_token;
          this.userDisplayName = loggedInUser.getBasicProfile().getName();
      });
  }
  </code></pre>
  
  <p>I did need to import the <code>_zone</code> object: <code>import {Component, NgZone} from "angular2/core";</code></p>
  
  <p>I also needed to inject it as suggested in the answer via the class's contructor: <code>constructor(private _zone: NgZone) { }</code></p>