The best structure of Angularjs project
Bài đăng này đã không được cập nhật trong 8 năm
Tổng quan
Angularjs là một JS Framework nổi tiếng của Google. Nó được ứng dụng rất nhiều trong các dự án web hiện nay. Angular có rất nhiều tính năng và ưu điểm tuyệt vời. Bạn muốn áp dụng ngay vào dự án của mình. Điều đầu tiên cần làm là tìm hiểu cấu trúc của nó.
Angularjs có khá nhiều lựa chọn để cấu trúc project của bạn như:
- Chuẩn MVC: cấu trúc theo thành phần của Angularjs như controllers, directives, services, views ...
app/
----- controllers/
---------- login.controller.js
---------- user.controller.js
---------- post.controller.js
----- directives/
---------- main.directive.js
---------- user.directive.js
----- services/
---------- user.service.js
---------- post.service.js
----- app.js
------views/
---------- login.html
---------- user.html
---------- index.html
- Cấu trúc theo module: cấu trúc thư mục theo các feature của dự án. Mỗi feature được đặt trong một folder riêng. Ví du: login, users, products, posts ...
app/
----- core/
---------- core.module.js
---------- core.service.js
----- login/
---------- login.controller.js
---------- login.service.js
----- users/
---------- user.controller.js
---------- user.directive.js
----- posts/
---------- post.controller.js
---------- post.config.js
----- app.route.js
----- app.module.js
Theo mình cấu trúc theo module ưu biệt hơn hẳn. Nó có tính mở rộng, cấu trúc rõ ràng, dễ bảo trì, nhất là các dự án lớn; hiện được các kĩ sư Google khuyến khích.
Xây dựng ứng dụng
Cấu trúc ứng dụng
Chúng ta sẽ làm một ứng dụng nhỏ có các chức năng:
- Đăng nhập
- Landing page
Ở đây mình dùng bower
để quản lý các thư viện JS. Các bước cài đặt các bạn có thể tham khảo tại đây
Tạo thư mục của project có cấu trúc như sau:
mkdir angular
cd angular
angular
---- app/
---- bower_components/
---- bower.json
---- data/
---- .htaccess
---- index.html
Giải thích:
app
: thư mục chứa tất cả code angularjsbower_components
: thư mục chứa các thư viện được cài đặt thông quabower
từ file configbower.json
bower.json
có file khai báo các thư viện cần thiết cho dự án. Nọi dung như sau:
// bower.json
{
"name": "angularjs-test",
"description": "",
"main": "",
"authors": [
"Nguyen Quoc Dat <datnq2010@gmail.com>"
],
"license": "MIT",
"homepage": "",
"ignore": [
"**/.*",
"node_modules",
"bower_components"
],
"dependencies": {
"angular": "1",
"angular-ui-router": "ui-router#^0.3.1",
"bootstrap": "^3.3.7",
"ngstorage": "^0.3.11"
}
}
- Để cài đặt các thư viện JS cần thiết, chúng ta sẽ cài các vendor sau: `angular` version `1`, `ui-router`, `ngstorage`.
- Run command sau trên terminal:
- `bower install`
data
: Thư mục chứa các dữ liệu để được gọi từapi
..htaccess
: File rewrite url choappache
để tạo friendly url trongui-router
// .htaccess
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule (.*) /index.html [L]
</IfModule>
index.html
: File index của ứng dụng
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<base href="/">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<nav class="navbar navbar-default" ng-include="'app/header/header.html'">
</nav>
<div ui-view></div>
</div>
</div>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="bower_components/ngstorage/ngStorage.min.js"></script>
<script src="app/core/core.module.js"></script>
<script src="app/core/auth.service.js"></script>
<script src="app/header/header.module.js"></script>
<script src="app/header/header.controller.js"></script>
<script src="app/login/login.module.js"></script>
<script src="app/login/login.config.js"></script>
<script src="app/login/login.controller.js"></script>
<script src="app/landing/landing.module.js"></script>
<script src="app/landing/landing.config.js"></script>
<script src="app/landing/landing.controller.js"></script>
<script src="app/app.module.js"></script>
<script src="app/app.config.js"></script>
</body>
</html>
Tạo các file và thư mục như sau trong thư mục app
.
angular
---- app
-------- app.config.js
-------- app.module.js
-------- core/
-------------core.module.js
-------------auth.service.js
-------- header/
-------------header.module.js
-------------header.controller.js
-------- landing/
-------------landing.module.js
-------------landing.config.js
-------------landing.controller.js
-------- login/
-------------login.module.js
-------------login.config.js
-------------login.controller.js
Giải thích:
app.module.js
: module chính của ứng ứng dụng.
(function() {
"use strict";
angular.module('app', ['app.core', 'app.header', 'app.landing', 'app.login']);
})();
-
app
là module chính của ứng dụng, dependency inject các module conapp.core
,app.header
,app.login
. -
app.core
là module core của ứng dụng, nó sẽ load các dependency vendor của toàn bộ ứng dụng nhưui.router
,ngStorage
...
// core.module.js
(function() {
'use strict';
angular.module('app.core', ['ui.router', 'ngStorage']);
})();
app.config.js
: file config chính của ứng dụng:
// app.config.js
(function () {
'use strict';
angular
.module('app')
.config(configure)
.run(runBlock);
configure.$inject = ['$locationProvider'];
function configure($locationProvider) {
$locationProvider.html5Mode(true);
}
runBlock.$inject = ['$http', '$rootScope', '$localStorage', '$state', 'AuthService'];
function runBlock( $http, $rootScope, $localStorage, $state, AuthService) {
if ($localStorage.currentUser) {
$http.defaults.headers.common.Authorization = 'Bearer ' + $localStorage.currentUser.token;
AuthService.updateCurrentUser($localStorage.currentUser.token, $localStorage.currentUser.username);
}
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, options){
if (toState.name == 'login' || toState.name == 'landing') {
} else {
if (!AuthService.isAuthenticated()) {
event.preventDefault();
$state.go('login');
}
}
});
}
})();
Chúng ta sẽ config url
theo html5Mode
để tạo pretty url.
AuthService
: là service xử lý và lưu trữ thông tin login của user, token. Mình sẽ sử dụng $localStorage
để lưu trữ các thông tin này thay vì sử dụng cookie
.
auth.service.js
:
(function() {
'use strict';
angular.module('app.core').factory('AuthService', AuthService);
AuthService.$inject = ['$http', '$localStorage'];
function AuthService($http, $localStorage) {
var authService = {
currentUser: {
token: null,
username: null
},
login: login,
logout: logout,
updateCurrentUser: function(token, username) {
this.currentUser.token = token;
this.currentUser.username = username;
},
isAuthenticated: function() {
return this.currentUser.token ? true : false;
}
}
return authService;
function login(email, password) {
return $http.post('/data/login.json', {
email: email,
password: password
}).then(function(data, status, headers, config) {
var res = data.data;
if (res.status) {
$http.defaults.headers.common.Authorization = 'Bearer ' + res.data.token;
$localStorage.currentUser = {
username: res.data.name,
token: res.data.token
};
authService.currentUser.token = res.data.token;
authService.currentUser.username = res.data.name;
}
return;
});
}
function logout() {
$http.defaults.headers.common.Authorization = null;
$localStorage.currentUser = null;
authService.currentUser.token = null;
authService.currentUser.username = null;
return;
}
}
})()
AuthService
có các thuộc tính thông tin đăng nhậpcurrentUser
,login
,logout
. Khi user login sẽ api login vớiemail
,password
. Ở đây để đơn giản mình sẽ tạo ra các data mẫujson
ở thư mụcdata
. Ví dụ: loginlogin.json
, danh sách userusers.json
giả lập kết quả trả về từ api.
// login.json
{
"status": true,
"data": {
"token": "xxx",
"id": 1,
"name": "datnq"
}
}
Như vậy khi login thành công mình sẽ lưu trữ thông tin của user vào localStorage
. Khi logout thì mình sẽ xóa thông tin của user trong localStorage
.
Module app.login
login.module.js
// login.module.js
(function() {
'use strict';
angular.module('app.login', ['app.core']);
})();
Chú ý app.login
sẽ inject module core của ứng dụng app.core
2. login.config.js
để config route login
(function() {
'use strict';
angular.module('app.login').config(config);
function config($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/landing");
$stateProvider.state('login', {
url: "/login",
templateUrl: "app/login/login.html",
controller: "LoginController",
controllerAs: "vm"
})
}
})();
login.controller.js
: Controller login sẽ injectAuthService
.
(function() {
'use strict';
angular
.module('app.login')
.controller('LoginController', LoginController);
LoginController.$inject = ['$state', '$http', 'AuthService'];
function LoginController ($state, $http, AuthService) {
var vm = this;
vm.email = '';
vm.password = '';
vm.login = login;
function login() {
AuthService
.login(vm.email, vm.password)
.then(
function(data, status, headers, config) {
if (AuthService.isAuthenticated)
return $state.go('landing');
},
function (error) {
alert(error);
}
);
};
}
})();
Chúng tiếp tục xây dựng chức năng landing page
.
Module app.landing
landing.module.js
: khởi tạo moduleapp.landing
. Ở đây moduleapp.landing
sẽ inject module chungapp.core
của ứng dụng.
// landing.module.js
(function() {
'use strict';
// angular
angular.module('app.landing', ['app.core']);
})();
landing.config.js
: config url route cho trang landing page
(function() {
'use strict';
angular
.module('app.landing')
.config(config);
config.$inject = ['$stateProvider', '$urlRouterProvider'];
function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('landing', {
url: "/landing",
templateUrl: "app/landing/landing.html",
controller: "LandingController",
controllerAs: "vm"
})
}
})();
landing.controller.js
: Controller landing page. Mình sẽ check nếu user login rồi sẽ hiển thị câu chào. Nếu chưa sẽ hiển thị yêu cầu login.AuthService.currentUser()
sẽ get thông tin của user login.
landing.html
: view landing
<div class="panel panel-default" ng-controller="LandingController as vm">
<div class="panel-heading">
<h3 class="panel-title">
Landing page
</h3>
</div>
<div class="panel-body">
Angularjs structure
<div ng-if="vm.currentUser.username">
Hello <b> {{vm.currentUser.username}} </b>!
</div>
<div ng-if="!vm.currentUser.username">
Hello guess, please login!
</div>
</div>
</div>
Module app.header
Module này để xử lý phần header bar. Phần này tương tự phần landing
.
header.module.js
(function() {
'use strict';
angular.module('app.header', ['app.core']);
})();
header.controller.js
: header controller
(function() {
'use strict';
angular
.module('app.header')
.controller('HeaderController', HeaderController);
HeaderController.$inject = ['AuthService', '$state'];
function HeaderController (AuthService, $state) {
var vm = this;
vm.currentUser = AuthService.currentUser;
vm.logout = logout;
function logout() {
AuthService.logout();
$state.go('landing');
}
}
})();
header.html
: header view
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" ng-controller="HeaderController as vm">
<ul class="nav navbar-nav">
<li>
<a ui-sref="landing">
Home
</a>
</li>
<li ng-if="vm.currentUser.username">
<a>
Hello
<b>
{{vm.currentUser.username}}
</b>
</a>
</li>
<li ng-if="vm.currentUser.username">
<a href="#" ng-click="vm.logout();">
Logout
</a>
</li>
<li ng-if="!vm.currentUser.username">
<a ui-sref="login">
Login
</a>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
Mở trình duyệt lên và xem thành quả của chúng ta nào:
- Chưa login:
- Login thành công:
Kết luận
All rights reserved