разделить приложение angularjs на компоненты с внедрением зависимостей маршрутизации

для данного веб-приложения, например, если 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.wall, поскольку стена должна объявлять свои собственные правила маршрутизации.

эта инъекция зависимостей выполнима?


person Zalaboza    schedule 01.10.2015    source источник
comment
Это слишком широкая тема для StackOverflow, и вы задаете слишком много разных вопросов. В Интернете есть много руководств по стилю Angular, но в конечном итоге все сводится к предпочтениям.   -  person Anid Monsur    schedule 01.10.2015
comment
@AnidMonsur извините, сначала я немного устроил мозговой штурм. я добавил небольшое редактирование, которое заключает вопрос в 4 строки!   -  person Zalaboza    schedule 01.10.2015
comment
Это выглядит как круговая зависимость, и Angular, скорее всего, вернет ошибка при попытке.   -  person Boaz - CorporateShillExchange    schedule 01.10.2015
comment
@Boaz именно поэтому я пометил вопрос circular-reference, так как же люди организуют код в такой ситуации?   -  person Zalaboza    schedule 01.10.2015
comment
Этот подход во многом похож на горячее полотенце Джона Папы, но он внедряет каждый модуль в основной модуль приложения. Возможно, вы сможете получить некоторое представление, взглянув на это.   -  person Mike Feltman    schedule 01.10.2015


Ответы (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-

///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. Информация о $пользователе доступна для всех модулей, 2. Модуль выдвигает себя на боковую панель, 3. Маршруты объявляются внутри каждого модуля в его собственном блоке конфигурации. 4. добавление нового модуля создаю новую папку, добавляю ссылку на связывающий модуль "залабанный в этом примере". и я готов идти, с аутентификацией и всем остальным :-)

person Zalaboza    schedule 02.10.2015