谷歌登录的网站和角2使用打字稿 [英] Google Sign-In for Websites and Angular 2 using Typescript

查看:263
本文介绍了谷歌登录的网站和角2使用打字稿的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要建一个具有pretty标准的RESTful Web服务来处理持久和复杂的业务逻辑的网站。我建立消费该服务的用户界面使用角2 写在打字稿组成部分。

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 Angular 2 with components written in TypeScript.

而不是建立自己的认证系统,我希望能依靠谷歌登入用于网站。这个想法是,用户将来到现场,通过提供有框架登录,然后沿着导致ID令牌,该服务器托管RESTful服务则可以验证发送。

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.

在谷歌登录的文档之外,还有<一个href=\"https://developers.google.com/identity/sign-in/web/build-button#customizing_the_automatically_rendered_sign-in_button_recommended\"相对=nofollow>创建通过JavaScript 中的登录按钮,这就是需要做的,因为登录按钮被在角模板,动态呈现的指令。的模板的相关部分:

In the Google Sign-In documentation there are instructions for creating the login button via JavaScript which is what needs to happen since the login button is being rendered dynamically in an Angular template. The relevant portion of the template:

<div class="login-wrapper">
  <p>You need to log in.</p>
  <div id="{{googleLoginButtonId}}"></div>
</div>
<div class="main-application">
  <p>Hello, {{userDisplayName}}!</p>
</div>

和在打字稿的角2组件定义:

And the Angular 2 component definition in Typescript:

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);
  }
}

基本流程进行:


  1. 角渲染模板和消息你好,空!所示。

  2. ngAfterViewInit 挂钩被触发, gapi.signin2.render(...)方法被调用哪个转换空div到谷歌登录按钮。这工作正常,点击该按钮会触发登录过程。

  3. 这也是在用户登录后附加组件的 onGoogleLoginSuccess 方法实际处理返回的标记。

  4. 角检测的 userDisplayName 属性更改和更新页面现在显示Hello,克雷格(或任何你的名字是)!

  1. Angular renders the template and the message "Hello, empty!" is shown.
  2. The ngAfterViewInit hook is fired and the gapi.signin2.render(...) 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.
  3. This also attaches the component's onGoogleLoginSuccess method to actually process the returned token after a user logs in.
  4. Angular detects that the userDisplayName property has changed and updates the page to now display "Hello, Craig (or whatever your name is)!".

这是出现的第一个问题是在 onGoogleLoginSuccess 方法。注意的console.log(...)调用在构造,并在该方法。正如预期的那样,一个在构造返回角度成分。在 onGoogleLoginSuccess 的方法之一,然而,返回的JavaScript 窗口对象。

The first problem that occurs is in the onGoogleLoginSuccess method. Notice the console.log(...) calls in the constructor and in that method. As expected, the one in the constructor returns the Angular component. The one in the onGoogleLoginSuccess method, however, returns the JavaScript window object.

所以看起来上下文中跳跃出谷歌的登录逻辑的过程,所以我的下​​一步是尝试引入是迷路jQuery的 $。代理来电挂断到正确的上下文。所以我加入导入jQuery命名空间声明变量$:任何到组件的顶部,然后将其转换的内容 ngAfterViewInit 方法是:

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 $.proxy call to hang on to the correct context. So I import the jQuery namespace by adding declare var $:any; to the top of the component and then convert the contents of the ngAfterViewInit method to be:

// 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"
      });
}

补充说,之后,两个的console.log 调用返回相同的对象,这样的属性值,现在更新正确。第二个日志消息显示与预期更新属性值的对象。

After adding that, the two console.log 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.

可惜的是,角模板不会被发生这种情况时更新。调试时,我无意中发现,我认为解释是怎么回事的东西。我添加了以下行 ngAfterViewInit 挂钩的末尾:

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 ngAfterViewInit hook:

setTimeout(function() {
  this.googleLoginButtonId = this.googleLoginButtonId },
  5000);

这实在不应该做任何事情。它只是等待五秒钟挂钩结束后,然后设置一个属性值等于本身。然而,随着地方就行了你好,空!消息变成你好,克雷格!有关网页5秒后加载。这表明,我认为只是角度不注意到该属性值是在 onGoogleLoginSuccess 方法改变。所以,当别的东西恰好通知角的属性值发生了变化(如上述否则无用的自我分配),角唤醒和更新的一切。

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 "Hello, empty!" message turns into "Hello, Craig!" 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 onGoogleLoginSuccess 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.

显然,这不是一个黑客我想在的地方离开,所以我想知道如果任何角度专家那里可以给我介绍?有一些电话,我应该做强制角注意到一些特性发生了改变?

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?

已更新2016年2月21日所提供的清晰度上解决了这个问题的明确的答案

我最终需要使用在所选择的答案中的建议的两片。

I ended up needing to use both pieces of the suggestion provided in the selected answer.

首先,正如所说,我需要转换的 onGoogleLoginSuccess 方法使用一个箭头的功能。其次,我需要让使用 NgZone 的对象,以确保在发生一个上下文,其中角是知道的属性更新。因此,最终的方法结束了看起来像

First, exactly as suggested, I needed to convert the onGoogleLoginSuccess method to use an arrow function. Secondly, I needed to make use of an NgZone 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

onGoogleLoginSuccess = (loggedInUser) => {
    this._zone.run(() => {
        this.userAuthToken = loggedInUser.getAuthResponse().id_token;
        this.userDisplayName = loggedInUser.getBasicProfile().getName();
    });
}

我确实需要导入 _zone 对象:进口{组件,NgZone}从angular2 /芯;

我还需要注入它作为通过类的构造器中的回答表明:构造函数(私人_zone:NgZone){}

I also needed to inject it as suggested in the answer via the class's contructor: constructor(private _zone: NgZone) { }

推荐答案

有关您的第一个问题的解决方案是使用的箭头功能,以$的对$ pserve背景这个

For your first problem solution is to use arrow function which will preserve context of this :

  onGoogleLoginSuccess = (loggedInUser) => {
    this.userAuthToken = loggedInUser.getAuthResponse().id_token;
    this.userDisplayName = loggedInUser.getBasicProfile().getName();
    console.log(this);
  }

第二个问题是发生,因为第三方脚本的角度范围之外运行。角使用所以,当你运行的东西,例如的setTimeout(),这是猴子修补在运行区,角会得到通知。你会在区域中运行的jQuery是这样的:

Second issue is happening because third-party scripts run outside the context of Angular. Angular uses zones so when you run something, for example setTimeout(), which is monkey-patched to run in the zone, Angular will get notified. You would run jQuery in zone like this:

  constructor(private zone: NgZone) {
    this.zone.run(() => {
      $.proxy(this.onGoogleLoginSuccess, this);
    });
  }

有许多问题/约与当时很多更好的解释我的,如果你想知道更多区域的答案,但如果你使用箭头功能它不应该为你的例子是一个问题。

There are many questions/answers about the zone with much better explanations then mine, if you want to know more, but it shouldn't be an issue for your example if you use arrow function.

这篇关于谷歌登录的网站和角2使用打字稿的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆