将 angularjs 应用程序拆分为具有路由依赖项注入的组件
split angularjs application into components with routing dependency injection
对于给定的 webapp - 例如 facebook- ,我想分成不同的模块
每个模块仅依赖于核心,并且不知道任何其他组件 - 所以将来如果我想添加或删除我所要做的就是开发这个功能及其 html 和 js 以及它自己内部的指令,只需在核心模块中添加依赖项,我就可以开始了。
例如应用程序将包含
1.墙 "path = "/components/wall.js"
2. 用户配置文件“/components/profile.js”
3.聊天“/components/chat.js
所有人都需要知道当前登录用户的详细信息,因此核心模块可能会通过将用户详细信息公开给 $rootScope 来处理此问题。 "/core.js"
然后整个应用程序用户必须登录才能访问,所以我会让 core.js 处理所有身份验证
编辑以缩小问题范围
var core = angular.module("core", ['core.wall']);
var wall = angular.module("core.wall", []);
现在 core DEPENDE on wall,但在我的设计中,wall 是依赖于 core 的。但与此同时,核心路由被 core.wall 更改,因为 wall 应该声明自己的路由规则。
这种依赖注入可行吗?
所以我没有得到任何答案,但经过大量尝试后我找到了解决方案。
Angularjs 模块的 DI(依赖注入)工作如下。
- 当你 bootstrap 一个模块自动使用
ng-app="module"
或手动触发 angular.bootstrap(document,"module");
时,首先发生的事情是它的所有依赖项都被循环并且所有配置块 运行.
//我创建了一个 github 示例
https://github.com/alzalabany/angular-material-modular-starter/
示例:
angular.module('zalabany',['app.core','app.wall','app.blog']);
angular.bootstrap(document, ['zalabany']);
//1-->app.core config run, app.wall config run, app.blog config run, zalabany.config runs last
//2-->then .run blocks run in same order.
所以,因为我们试图在本质上进行模块化。正如我解释的那样,我的问题的核心不应该依赖于其他 app module
但所有其他模块都依赖于它。为此,我使用了一个中间模块,link 它们在一起。
最终代码。 -即将上传 git-
///Linking module, sole function is to connect all modules sharing same $rootScope and making sure system loads in correct order
angular.module('zalabany',['app.core','app.wall','app.blog']);
//I'm the Core.js i depend on external libs only. i'm not aware of my own system modules.
angular.module('app.core', ['ui.router', 'ngAnimate', 'toastr', 'ngMaterial','ngMdIcons'])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
///http interceptor in case 403,401 on any request, redirect to login right away.
$httpProvider.interceptors.push(function($q, $rootScope, $injector, $timeout, $window) {
var toastr, $state, $http;
//timeout is used to prevent circuler dependency error !
$timeout(function() {
toastr = $injector.get('toastr');
$http = $injector.get('$http');
$state = $injector.get('$state');
});
return {
responseError: function(rejection) {
if (rejection.data && rejection.data.hasOwnProperty('message')) {
toastr.error('request failed. try again later');
}
if (rejection.status === 401 || rejection.status === 403) {
console.log('rejected and redirecting', rejection);
$state.go('login');
}
return $q.reject(rejection);
}
};
});
$urlRouterProvider.otherwise("/login");
$stateProvider
.state('login', {
url: "/login",
templateUrl: "modules/core/login.html"
});
console.log('im config core');
})
.controller('loginCtrl', function($scope,$user,$rootScope){//remember $user is available every where
var self=this;
this.username = $user.username;
if($user.token && $user.id){
//validate token by sending get to auth.
$http.defaults.headers.common["auth-token"] = $user.token;
$http.defaults.headers.common["auth-uid"] = $user.id;
$http.get($oauth).then(function(){$rootScope.Login($user);},$rootScope.Logout);
}
this.login= function(){
$http.post($oauth,{username:self.username,password:self.password})
.then(function(r){
$rootScope.Login(r); //use login method on root to expose it for all modules
});
}
})
.run(function($rootScope, $state, $user,$http,$oauth) {
///$rootscope is shared between all modules. so i use it for sharing auth data since its just an object.
$rootScope.$user = $user;
$rootScope.$homepage = null;
//default home page of appchild should overide it;
//all children modules can edit this.
///FUNTION 1.
///LISTEN FOR ROUTE CHANGE AND PREVENT IF USER IS NOT LOGGED IN
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
if (!$rootScope.$user.hasOwnProperty('token') && toState.name !== 'login') {
console.log('prevented');
event.preventDefault();
$state.go('login');
}
});
$rootScope.Login = function(r){
// login login ...
$http.defaults.headers.common["auth-uid"] = r.token;
angular.module('zalabany').value('$user',r);
console.log('oki lets go hom',$state.go($rootScope.$homepage));
}
$rootScope.Logout = function(){
window.localStorage.clear();
$state.go('login');
}
});
///BOOTSTRAP
$(function(){
$.getJSON('PING API WITH TOKEN FROM LOCALSTORAGE', function(json) {
$user = json || data;//json is our user record
}).fail(function() {
$user=data;
window.localStorage.clear();
console.log( "login error" );
}).always(function() {
angular.module('app.core')
.value('$user',$user);
angular.bootstrap(document, ['zalabany']); //bootstrap the link module
});
});
从现在开始,向我的应用添加新组件就像
一样简单
angular.module('app.wall', ['app.core'])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('wall', {
url: "/wall",
templateUrl: "modules/wall/wall.html"
});
})
.run(function($rootScope, $state, $user,$http,$oauth) {
$rootScope.$homepage = 'wall';//Set homepage to me
// or i can use
$rootScope.$homepage = $rootScope.$homepage || 'wall';//set homepage to me if no other modules declared it it.
//Push me into the sidebar.
$rootScope.$sidebar.push({order:1, link:'/wall',title:'Feed',icon:'fa fa-star'});
});
这种结构的好处:-
1. i hv $user 信息可用于所有模块,
2. 模块自动推送到侧边栏,
3. 路由在每个模块内部的配置块中声明。
4. 添加新模块 我创建新文件夹,将 link 添加到 linking 模块 "zalabany in this example"。我很高兴,身份验证和一切:-)
对于给定的 webapp - 例如 facebook- ,我想分成不同的模块
每个模块仅依赖于核心,并且不知道任何其他组件 - 所以将来如果我想添加或删除我所要做的就是开发这个功能及其 html 和 js 以及它自己内部的指令,只需在核心模块中添加依赖项,我就可以开始了。
例如应用程序将包含 1.墙 "path = "/components/wall.js" 2. 用户配置文件“/components/profile.js” 3.聊天“/components/chat.js
所有人都需要知道当前登录用户的详细信息,因此核心模块可能会通过将用户详细信息公开给 $rootScope 来处理此问题。 "/core.js"
然后整个应用程序用户必须登录才能访问,所以我会让 core.js 处理所有身份验证
编辑以缩小问题范围
var core = angular.module("core", ['core.wall']);
var wall = angular.module("core.wall", []);
现在 core DEPENDE on wall,但在我的设计中,wall 是依赖于 core 的。但与此同时,核心路由被 core.wall 更改,因为 wall 应该声明自己的路由规则。
这种依赖注入可行吗?
所以我没有得到任何答案,但经过大量尝试后我找到了解决方案。
Angularjs 模块的 DI(依赖注入)工作如下。
- 当你 bootstrap 一个模块自动使用
ng-app="module"
或手动触发angular.bootstrap(document,"module");
时,首先发生的事情是它的所有依赖项都被循环并且所有配置块 运行.
//我创建了一个 github 示例 https://github.com/alzalabany/angular-material-modular-starter/
示例:
angular.module('zalabany',['app.core','app.wall','app.blog']);
angular.bootstrap(document, ['zalabany']);
//1-->app.core config run, app.wall config run, app.blog config run, zalabany.config runs last
//2-->then .run blocks run in same order.
所以,因为我们试图在本质上进行模块化。正如我解释的那样,我的问题的核心不应该依赖于其他 app module
但所有其他模块都依赖于它。为此,我使用了一个中间模块,link 它们在一起。
最终代码。 -即将上传 git-
///Linking module, sole function is to connect all modules sharing same $rootScope and making sure system loads in correct order
angular.module('zalabany',['app.core','app.wall','app.blog']);
//I'm the Core.js i depend on external libs only. i'm not aware of my own system modules.
angular.module('app.core', ['ui.router', 'ngAnimate', 'toastr', 'ngMaterial','ngMdIcons'])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
///http interceptor in case 403,401 on any request, redirect to login right away.
$httpProvider.interceptors.push(function($q, $rootScope, $injector, $timeout, $window) {
var toastr, $state, $http;
//timeout is used to prevent circuler dependency error !
$timeout(function() {
toastr = $injector.get('toastr');
$http = $injector.get('$http');
$state = $injector.get('$state');
});
return {
responseError: function(rejection) {
if (rejection.data && rejection.data.hasOwnProperty('message')) {
toastr.error('request failed. try again later');
}
if (rejection.status === 401 || rejection.status === 403) {
console.log('rejected and redirecting', rejection);
$state.go('login');
}
return $q.reject(rejection);
}
};
});
$urlRouterProvider.otherwise("/login");
$stateProvider
.state('login', {
url: "/login",
templateUrl: "modules/core/login.html"
});
console.log('im config core');
})
.controller('loginCtrl', function($scope,$user,$rootScope){//remember $user is available every where
var self=this;
this.username = $user.username;
if($user.token && $user.id){
//validate token by sending get to auth.
$http.defaults.headers.common["auth-token"] = $user.token;
$http.defaults.headers.common["auth-uid"] = $user.id;
$http.get($oauth).then(function(){$rootScope.Login($user);},$rootScope.Logout);
}
this.login= function(){
$http.post($oauth,{username:self.username,password:self.password})
.then(function(r){
$rootScope.Login(r); //use login method on root to expose it for all modules
});
}
})
.run(function($rootScope, $state, $user,$http,$oauth) {
///$rootscope is shared between all modules. so i use it for sharing auth data since its just an object.
$rootScope.$user = $user;
$rootScope.$homepage = null;
//default home page of appchild should overide it;
//all children modules can edit this.
///FUNTION 1.
///LISTEN FOR ROUTE CHANGE AND PREVENT IF USER IS NOT LOGGED IN
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
if (!$rootScope.$user.hasOwnProperty('token') && toState.name !== 'login') {
console.log('prevented');
event.preventDefault();
$state.go('login');
}
});
$rootScope.Login = function(r){
// login login ...
$http.defaults.headers.common["auth-uid"] = r.token;
angular.module('zalabany').value('$user',r);
console.log('oki lets go hom',$state.go($rootScope.$homepage));
}
$rootScope.Logout = function(){
window.localStorage.clear();
$state.go('login');
}
});
///BOOTSTRAP
$(function(){
$.getJSON('PING API WITH TOKEN FROM LOCALSTORAGE', function(json) {
$user = json || data;//json is our user record
}).fail(function() {
$user=data;
window.localStorage.clear();
console.log( "login error" );
}).always(function() {
angular.module('app.core')
.value('$user',$user);
angular.bootstrap(document, ['zalabany']); //bootstrap the link module
});
});
从现在开始,向我的应用添加新组件就像
一样简单angular.module('app.wall', ['app.core'])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('wall', {
url: "/wall",
templateUrl: "modules/wall/wall.html"
});
})
.run(function($rootScope, $state, $user,$http,$oauth) {
$rootScope.$homepage = 'wall';//Set homepage to me
// or i can use
$rootScope.$homepage = $rootScope.$homepage || 'wall';//set homepage to me if no other modules declared it it.
//Push me into the sidebar.
$rootScope.$sidebar.push({order:1, link:'/wall',title:'Feed',icon:'fa fa-star'});
});
这种结构的好处:- 1. i hv $user 信息可用于所有模块, 2. 模块自动推送到侧边栏, 3. 路由在每个模块内部的配置块中声明。 4. 添加新模块 我创建新文件夹,将 link 添加到 linking 模块 "zalabany in this example"。我很高兴,身份验证和一切:-)