2

对于给定web应用 - 例如如果facebook-,我想分成不同的模块分裂angularjs应用成组件与路由依赖注入

每个模块都仅依赖于核心并且不知道任何其它组分的 - 所以在将来,如果我想添加或删除一个功能,我所要做的就是用它的html和js和指令开发这个功能,并且只需在核心模块中添加依赖关系,然后即可使用。

例如应用程序将含有 1.壁 “路径= ”/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", []); 

现在核心DEPENDE在墙上,但在我的设计,墙面是取决于核心之一。但同时,核心路由被core.wall改变,因为wall应该声明自己的路由规则。

这是依赖注入可行吗?

+0

这是过于广泛,StackOverflow的一个话题,你要价太高许多不同的问题。网上有很多Angular风格的指南,但最终这些都归结为偏好。 –

+0

@AnidMonsur对不起,我有点头脑风暴。我添加了一个小小的编辑,用4行来完成这个问题! – Zalaboza

+0

这看起来像[循环依赖项](http://stackoverflow.com/questions/19344214/problems-with-circular-dependency-and-oop-in-angularjs),如果尝试,Angular可能会返回错误。 – Boaz

回答

1

所以我没有得到任何答案,但大量玩耍后,我想出了一个解决方案。

模块的Angularjs DI(依赖注入)工作方式如下。

  1. 当你使用引导或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依赖于它。所以为此,我使用了一个中间模块,将它们链接在一起。

最终代码。 - 将会上传的git soon-

///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。我可以为所有模块提供hv $用户信息, 2.模块将它自己推送到边栏, 3.路由在每个模块内部在其自己的配置块中声明。 4.添加新模块我创建新文件夹,添加链接到链接模块“zalabany在这个例子”。我好去,身份验证和一切:-)