Skip to content

AngularJS Frontend

Visão Geral

O frontend da aplicação UNICEF Portugal é uma Single Page Application (SPA) construída com AngularJS 1.x. Não é um processo separado -- é HTML e JavaScript estático servido a partir do mesmo Azure App Service que aloja o Umbraco.

Como é Carregado

O AngularJS não corre separadamente do Umbraco. É carregado através de um template Razor do Umbraco chamado StartView.cshtml (Web/Views/StartView.cshtml).

Este template:

  1. Herda de UmbracoTemplatePage (é um template Umbraco normal)
  2. Carrega o nó da homepage para obter o ID do Google Analytics
  3. Renderiza a página HTML completa com <html ng-app="unicef">
  4. Inclui os ficheiros CSS e JS da aplicação Angular (versão minificada)
  5. Define a estrutura de layout: sidebar, header, <main ui-view>, footer

Quando o Umbraco recebe um pedido para qualquer URL, serve este template. O AngularJS então "toma conta" da navegação no browser, fazendo chamadas à API para obter o conteúdo de cada página.

Umbraco (StartView.cshtml)
  └── Serve HTML com ng-app="unicef"
        └── AngularJS faz bootstrap
              └── ui-router intercepta navegação
                    └── Chama /umbraco/Api/ContentApi/GetData/
                          └── Renderiza template de /Assets/ngviews/

Ficheiros Fonte

  • Desenvolvimento: Templates/app/index.html (versão não minificada, para referência)
  • Produção: O template Umbraco StartView.cshtml carrega /Assets/js/main.min.js e /Assets/css/main.min.css
  • IIS Express (local): Porta SSL 44388 (https://localhost:44388)

Routing

A aplicação utiliza angular-ui-router com HTML5 mode:

$locationProvider.html5Mode(true);

Existe um unico estado chamado "all" com uma rota catch-all:

URL: *myPath?q

Este estado intercepta toda a navegação do browser.

Fluxo de Carregamento

sequenceDiagram participant B as Browser participant R as ui-router participant C as Controller participant API as ContentApiController participant T as /Assets/ngviews/ B->>R: Navegacao para /qualquer-pagina R->>R: Estado "all" intercepta (*myPath) R->>API: Resolve: GET /umbraco/Api/ContentApi/GetData/?url=/qualquer-pagina API-->>R: JSON {data: {...}, meta: {template: "/Assets/ngviews/xyz.html"}} R->>C: Controller recebe dados C->>C: Processa: image crops, template URL, share links C->>T: ng-include carrega template T-->>B: Template renderizado com dados

Ciclo de Vida de um Pedido

  1. O utilizador navega para um URL (ex: /noticias/artigo-exemplo)
  2. O ui-router intercepta via catch-all *myPath
  3. No resolve do estado, é feita uma chamada à API:
    GET /umbraco/Api/ContentApi/GetData/?url=/noticias/artigo-exemplo
    
  4. A API retorna JSON com dois blocos:
  5. data: título, corpo, imagem, e outros campos do conteúdo
  6. meta: caminho do template (ex: "/Assets/ngviews/newsDetail.html")
  7. O controller processa a resposta: define crops de imagens, URL do template, links de partilha
  8. O template e carregado via ng-include:
    <div ng-include="vm.pageData.templateUrl"></div>
    

Estrutura de Layout

graph TB subgraph "Layout da Pagina" A["sidebar.html - ng-include"] B["header.html - ng-include"] C["main - ui-view - conteudo dinamico"] D["footer.html - ng-include"] end A --- B B --- C C --- D

Os componentes de layout são carregados via ng-include:

  • sidebar.html - Barra lateral
  • header.html - Cabeçalho
  • main (ui-view) - Conteúdo dinâmico, muda com cada página
  • footer.html - Rodapé

Templates

Os templates estão organizados em /Assets/ngviews/:

Assets/ngviews/
    components/     -- Componentes reutilizáveis
    layout/         -- Estrutura de layout (header, footer, sidebar)
    *.html          -- Templates de pagina (newsDetail, articleDetail, etc.)

Configuracao

No Web.config existe a seguinte definicao:

<add key="Template.Path" value="Assets/ngviews/" />

Esta configuração define o caminho base para os templates do frontend.

Versões: app vs dist

Pasta Uso Descrição
Templates/app/ Desenvolvimento Código fonte original, não minificado
Templates/dist/ Produção Build de produção, ficheiros minificados e concatenados

Impacto na Performance

Se o ContentApiController estiver lento (por exemplo, devido a bloat na base de dados com 1.6M de registos na tabela icUrlTracker), o spinner de carregamento fica visível indefinidamente. Isto acontece porque o AngularJS aguarda a resposta completa da API antes de renderizar qualquer conteúdo na página. Não existe timeout nem fallback -- a página simplesmente não carrega.