AngularJS+Satellizer+Node.js+MongoDB->Instagram-16

Build an Instagram clone with AngularJS, Satellizer, Node.js and MongoDB

16.回到客户端

让我们创建一个新用户,然后登陆。验证一下我们后台功能的实现是不是像预期一样可以开始工作了。

刷新浏览器,从顶部导航点击注册连接,填写注册资料然后点击注册按钮。

https://hackhands.com/wp-content/uploads/2014/11/Screenshot-2014-11-23-19.16.59.png

如果一切正常的话你应该会被重定向到这个页面:

https://hackhands.com/wp-content/uploads/2014/11/Screen-Shot-2014-11-23-at-7.38.03-PM.png

怎么回事?好的,默认的, Satellizer 会在用户注册成功之后自动登陆。你如果愿意你可以在 app.js 里面把它关掉:

<!-- lang: js -->
$authProvider.loginOnSignup = false;

现在你看到的是 home.html 模板。如果你还记得话,我们在这个页面有三种状态:

  • 用户被授权 (email & password 或者 OAuth 2.0) 并且有 Instagram 用户名。这意味着这个用户已经用 Instagram 注册或者说创建了一个 email 账号并且把它连接到了他/她的 Instagram 账号。
  • 用户没有被授权。
  • 用户被授权了但是没有 Instagram 用户名。在继续之前这个账号必须和 Instagram 连接起来。

为了能连接到 Instagram 账号,我们需要在 HomeCtrl controller 里面做一些改动。打开 controllers/home.js 然后把 $scope.linkInstagram 方法的代码换成下面这样:

<!-- lang: js -->
$scope.linkInstagram = function() {
  $auth.link('instagram')
    .then(function(response) {
      $window.localStorage.currentUser = JSON.stringify(response.data.user);
      $rootScope.currentUser = JSON.parse($window.localStorage.currentUser);
      API.getFeed().success(function(data) {
        $scope.photos = data;
      });
    });
};

这里唯一不一样的是我们在连接 Instagram 账号成功之后调用 API.getFeed() (我们之后要实现的)。一旦我们从服务器拿到数据,把它设置到 $scope.photos,Angular 的双向绑定会帮我们处理剩下的事情,把所有的照片显示到 Home 模版上。

在我们继续实现 API service 之前,我们在HomeCtrl controller 中添加如下代码:

<!-- lang: js -->
if ($auth.isAuthenticated() && ($rootScope.currentUser && $rootScope.currentUser.username)) {
  API.getFeed().success(function(data) {
    $scope.photos = data;
  });
}

它其实和上面我们刚才追加的代码是一样的。当页面加载之后,如果用户已通过认证,它会调用 API.getFeed(),从 Instagram 动态取得最新的照片。

https://hackhands.com/wp-content/uploads/2014/11/Screenshot-2014-11-25-20.38.09.png

注意: 别忘了把 API service 注入到 HomeCtrl controller ,就像上面那样。

现在唯一少的就是 API 服务本身了。在 client 目录下创建一个心的文件夹叫 services。我们在这里放我们自定义的 AngularJS services, factories, providers。在这篇教程中我们只有一个 service。

https://hackhands.com/wp-content/uploads/2014/11/Screenshot-2014-11-25-20.05.59.png

在新的 services 文件夹里面我们创建一个新的文件叫做 api.js,内容如下:

<!-- lang: js -->
angular.module('Instagram')
  .factory('API', function($http) {

    return {
      getFeed: function() {
        return $http.get('http://localhost:3000/api/feed');
      },
      getMediaById: function(id) {
        return $http.get('http://localhost:3000/api/media/' + id);
      },
      likeMedia: function(id) {
        return $http.post('http://localhost:3000/api/like', { mediaId: id });
      }
    }

  });

这个服务的主要目的是抽象我们发送到后台的 HTTP 请求。当你的应用变得复杂的时候,把它分离出来的好处就更加明显了。

最后,别忘记把这个服务在 index.html 里面引入:

<!-- lang: js -->
<script src="services/api.js"></script>

刷新浏览器,然后点击 Sign in with Instagram button。在你登陆了 Instagram 并且成功的授权这个应用,用你的 Instagram 基本信息之后,你会在 home 页面看到一个照片墙。

但是,你每刷新一次浏览器你就很操蛋的要重新在 Sign in with Instagram 页面上登陆一次。我们来改掉它。打开 app.js 然后把下面的代码加到 .run 里面:

<!-- lang: js -->
.run(function($rootScope, $window, $auth) {
  if ($auth.isAuthenticated()) {
    $rootScope.currentUser = JSON.parse($window.localStorage.currentUser);
  }
});

注意: 你必须把 .config 后面的分号删掉,以便它和 .run 这段构成一个方法链,要不然你会被提示 JavaScript 非法字符。

下面是完整代码:

<!-- lang: js -->
angular.module('Instagram', ['ngRoute', 'ngMessages', 'chieffancypants.loadingBar', 'satellizer'])
  .config(function($routeProvider, $authProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/home.html',
        controller: 'HomeCtrl'
      })
      .when('/login', {
        templateUrl: 'views/login.html',
        controller: 'LoginCtrl'
      })
      .when('/signup', {
        templateUrl: 'views/signup.html',
        controller: 'SignupCtrl'
      })
      .when('/photo/:id', {
        templateUrl: 'views/detail.html',
        controller: 'DetailCtrl'
      })
      .otherwise('/');

    $authProvider.loginUrl = 'http://localhost:3000/auth/login';
    $authProvider.signupUrl = 'http://localhost:3000/auth/signup';
    $authProvider.oauth2({
      name: 'instagram',
      url: 'http://localhost:3000/auth/instagram',
      redirectUri: 'http://localhost:8000',
      clientId: '799d1f8ea0e44ac8b70e7f18fcacedd1',
      requiredUrlParams: ['scope'],
      scope: ['likes'],
      scopeDelimiter: '+',
      authorizationEndpoint: 'https://api.instagram.com/oauth/authorize'
    });
  })
  .run(function($rootScope, $window, $auth) {
    if ($auth.isAuthenticated()) {
      $rootScope.currentUser = JSON.parse($window.localStorage.currentUser);
    }
  });

这允许我们把用户对象保存在浏览器的 local storage 里面,并指向 $rootScope.currentUser,这样就可以在 Angular 应用的全局对它进行访问了。

https://hackhands.com/wp-content/uploads/2014/11/Screenshot-2014-11-25-21.01.18.png

记住,在单页应用里面,当你刷新浏览器的时候,你的所有变更都会丢失,你的应用会被重置为原始状态。这就是为什么我们会在登陆成功之后,把用户对象保存在浏览器的 local storage 里面的原因了,当应用加载之后,我们把它还原回来。所以,当用户登出之后,把它从 local storage 中清除,这也就成了我们的责任了。

刷新页面,然后我们可以看到一切都如预期一样正常运作了:

https://lh5.googleusercontent.com/-Vtj80ERZNVM/VIiaM1oOv9I/AAAAAAAAEps/MudM6vnOSkw/w1982-h1290-no/Screenshot%2B2014-11-25%2B21.22.53.png

如果你还有问题,那么试试看在 JavaScript Console 里面运行 localStorage.clear() 来清除 local storage 然后创建一个新的用户账号试试。

你可能感兴趣的:(AngularJS,express,nodejs,node,node.js,OAuth,oauth2,Satellizer,OAuthn)