Build an Instagram clone with AngularJS, Satellizer, Node.js and MongoDB
让我们创建一个新用户,然后登陆。验证一下我们后台功能的实现是不是像预期一样可以开始工作了。
刷新浏览器,从顶部导航点击注册连接,填写注册资料然后点击注册按钮。
如果一切正常的话你应该会被重定向到这个页面:
怎么回事?好的,默认的, Satellizer 会在用户注册成功之后自动登陆。你如果愿意你可以在 app.js 里面把它关掉:
<!-- lang: js -->
$authProvider.loginOnSignup = false;
现在你看到的是 home.html 模板。如果你还记得话,我们在这个页面有三种状态:
为了能连接到 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 动态取得最新的照片。
注意: 别忘了把 API service 注入到 HomeCtrl controller ,就像上面那样。
现在唯一少的就是 API 服务本身了。在 client 目录下创建一个心的文件夹叫 services。我们在这里放我们自定义的 AngularJS services, factories, providers。在这篇教程中我们只有一个 service。
在新的 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 应用的全局对它进行访问了。
记住,在单页应用里面,当你刷新浏览器的时候,你的所有变更都会丢失,你的应用会被重置为原始状态。这就是为什么我们会在登陆成功之后,把用户对象保存在浏览器的 local storage 里面的原因了,当应用加载之后,我们把它还原回来。所以,当用户登出之后,把它从 local storage 中清除,这也就成了我们的责任了。
刷新页面,然后我们可以看到一切都如预期一样正常运作了:
如果你还有问题,那么试试看在 JavaScript Console 里面运行 localStorage.clear() 来清除 local storage 然后创建一个新的用户账号试试。