Árvore de páginas

Em resumo, toda aplicação centralizadora deve possuir um arquivo de configuração responsável por gerenciar o mapeamento de rotas do AngularJS para atender as necessidades da aplicação. As rotas estáticas devem ser adicionadas diretamente ao $stateProvider, as demais views da aplicação irão ser carregadas por exceção através do 'otherwise' do $urlRouterProvider.

Utilizando como base a aplicação de referencia, temos esta configuração definida no arquivo config-states.js. Esta configuração tem alta dependência da estrutura de pastas definida para as aplicações.

Por padrão, temos 2 modos de adicionar uma página a aplicação:

Estático

As páginas estáticas normalmente estão relacionas a aplicação de centralizadora. Normalmente páginas de configuração, informações e outras. Estas páginas podem ser adicionadas diretamente ao $stateProvider do AngularJS por não possuírem estados.

Exemplo
appStateConfig.$inject = ['$stateProvider', '$urlRouterProvider'];
function appStateConfig($stateProvider, $urlRouterProvider) {
        
	index.stateProvider = $stateProvider;

	// Views padrões da aplicação que não possuem 'states'.
    $stateProvider.state(
    	'about', {
        	url: '/html-app/about',
            templateUrl: '/html-app/html/about.html'
        }
	).state(
    	'blank', {
        	url: '/',
        	templateUrl: '/html-app/html/blank.html'
		}
	);

	...

} // appStateConfig

index.config(appStateConfig);

Dinâmico

Ao contrário das páginas estáticas as views dinâmicas possuem diferentes estados e confiam fortemente na estrutura definida para as aplicações. No caso da aplicação de referencia a chamada das views pode ser realizada a outros contextos, permitindo assim segmentar as aplicações. Entretanto, cada segmento da aplicação deverá seguir a estrutura padrão para que seja possível a interação das aplicações convencionais com a centralizadora. Por convenção neste exemplo utilizamos a seguinte especificação:

    - <contexto do produto>/<contexto da aplicação>/<contexto da view>/html/<view>/<view>.js

Para possibilitar esta estruturação e carregamento dinâmico, foi utilizado o AngularJS UI Router para permitir sejam feitas views com sub-view. Sendo necessário sobrescrever o $urlRouterProvider.otherwise para contemplar as requisições com base no contexto da aplicação e view.

Exemplo
appStateConfig.$inject = ['$stateProvider', '$urlRouterProvider'];
function appStateConfig($stateProvider, $urlRouterProvider) {

	index.stateProvider = $stateProvider;

	...

	$urlRouterProvider.otherwise(function ($injector, $location) {
            
		var view = '';
    	var contexto = '';
        var templateurl = '';
            
        var strs = $location.path().split('/');
            
        if (strs.length > 3) {
				contexto = strs[1] + '/' + strs[2];
				view = contexto + '/' + strs[3];
				templateurl = '/' + strs[1] + '/' + strs[2] + '/html/' + strs[3] + '/' + strs[3];
		}
 
        ...
            
        if (view !== "") {
        	requirejs([templateurl + '.js'], function () {
        
				var state = $injector.get('$state');
                var urlRouter = $injector.get('$urlRouter');

                if (state.get(view) == null) {
    
	            	index.stateProvider.state(view, {
                    	abstract: true,
                        template: '<ui-view/>'
					});
                
					index.stateProvider.state(view + '.start', {
						url: view,
	                    templateUrl: templateurl + '.html'
                    });
                }
                
			    if (strs.length > 3) {
            		urlRouter.sync();
                } else {
                    state.go(view + '.start');
                }
            });
        } else {
			return '/';
		}
	});

} // appStateConfig

index.config(appStateConfig);

Quanto as aplicações convencionais, para cada view é preciso definir um arquivo descritor da hierarquia de estados (<view>.js). Por padrão o framework procura por um 'state' do tipo '.start' para iniciar a view caso não seja especificado um 'state' na própria chamada:

Exemplo
define(['index', '/thf/html-sample/html/country/country-services.js'], function(index) {

    // Inicializa os states da aplicação.
    index.stateProvider
    
        // Estado pai, a hierarquia de states é feita através do '.', e todo estado novo 
        // tem que ter um estado pai, que nesse caso é abstrato. Este status precisa 
        // apenas de uma template com o elemento <ui-view> para conter os estados filhos.
        .state('thf/html-sample/country', {
            abstract: true,
            template: '<ui-view/>'
        })
    
         // Estado inicial da tela deve ser o estado pai com o sufixo '.start' este estado 
         // será ativado automaticamente quando a tela for carregada.
         //
         // A URL deve ser compatível com a tela inicial.
         // 
         // No estado também definimos o controller usado na template do estado, e definimos
         // o nome do controller em 'controllerAs' para ser utilizado na view.
         // também definimos a template ou templateUrl com o HTML da tela da view.
        .state('thf/html-sample/country.start', {
            url:'/thf/html-sample/country/',
            controller:'framework.country-list.Control',
            controllerAs: 'controller',
            templateUrl:'/thf/html-sample/html/country/country.list.html'
        })
    
        // Note que outros estados também são filhos com sufixos conforme o objetivo da tela,
        // assim como o padrão da URL, controller e template.
        .state('thf/html-sample/country.detail', {
            url:'/thf/html-sample/country/detail/:id',
            controller:'framework.country-detail.Control',
            controllerAs: 'controller',
            templateUrl:'/thf/html-sample/html/country/country.detail.html'
        })
        .state('thf/html-sample/country.edit', {
            url: '/thf/html-sample/country/edit/:id',
            controller: 'framework.country-edit.Control',
            controllerAs: 'controller',
            templateUrl: '/thf/html-sample/html/country/country.edit.html'
        })
        .state('thf/html-sample/country.new', {
            url: '/thf/html-sample/country/new',
            controller: 'framework.country-edit.Control',
            controllerAs: 'controller',
            templateUrl: '/thf/html-sample/html/country/country.edit.html'
        });
});

Observação: Com a utilização do RequireJS é possível separar o carregamento dos estados para a view dos serviços para a mesma. Portanto, ao definir o descritor de estados podemos solicitar que o mesmo carregue os arquivos de serviços para a view (country-services.js), caso o mesmo já não tenha sido carregado, para isto basta adicionar o caminho completo do arquivo na definição de dependências do RequireJS conforme exemplo acima.

Referencia Externa

  • Sem rótulos