Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web...

19
Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido ao servidor; o servidor recebe o pedido, encaminha-o para um controlador (routes to a controller), o controlador executa uma ação específica e cria uma vista que envia como resposta para o browser. Angular usa client-side routing muito semelhante no conceito, mas diferente na implementação. No routing client-side não é feito um pedido ao servidor sempre que o URL muda. As aplicações Angular são “Single Page Apps” (SPA) porque o servidor só transfere uma única página. Uma aplicação Angular é constituída por um conjunto de componentes e Angular através do routing (executando código JavaScript) mostra diferentes vistas (páginas) para diferentes áreas ou atividades, apresentando componentes diferentes. Como a aplicação é client-side, tecnicamente não seria necessário mudar o URL quando mudámos de página. Mas se usássemos o mesmo URL para todas as páginas não seria possível refrescar a página e manter a localização dentro da aplicação, não seria possível criar um bookmark da página nem partilhar o URL. Routing permite-nos definir diferentes strings URL, uma para cada área ou atividade da aplicação. Angular usa o modo de routing HTML5. Em HTML5 é possível criar programaticamente novas entradas da história do browser que mudam o URL mostrado, sem fazer um novo pedido ao servidor. Isto é possível através do método history.pushState. Uma boa prática em Angular é criar um módulo top-level, separado, dedicado ao routing e importado pelo módulo raiz AppModule. Assim, para adicionar Routing a uma aplicação Angular já existente, devemos usar o seguinte comando ng: > ng generate module app-routing --flat --module=app e fazer as modificações indicadas no tutorial tour-of-heroes (toh). É mais simples criar uma nova aplicação Angular com Routing usando o seguinte comando ng: > ng new AngularRouting --routing Neste caso não é necessário fazer qualquer modificação. Ficheiro app.module.ts: import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent

Transcript of Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web...

Page 1: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Angular Routing

As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser,

que faz um pedido ao servidor; o servidor recebe o pedido, encaminha-o para um controlador

(routes to a controller), o controlador executa uma ação específica e cria uma vista que envia

como resposta para o browser.

Angular usa client-side routing muito semelhante no conceito, mas diferente na

implementação. No routing client-side não é feito um pedido ao servidor sempre que o URL

muda. As aplicações Angular são “Single Page Apps” (SPA) porque o servidor só transfere uma

única página. Uma aplicação Angular é constituída por um conjunto de componentes e Angular

através do routing (executando código JavaScript) mostra diferentes vistas (páginas) para

diferentes áreas ou atividades, apresentando componentes diferentes.

Como a aplicação é client-side, tecnicamente não seria necessário mudar o URL quando

mudámos de página. Mas se usássemos o mesmo URL para todas as páginas não seria possível

refrescar a página e manter a localização dentro da aplicação, não seria possível criar um

bookmark da página nem partilhar o URL.

Routing permite-nos definir diferentes strings URL, uma para cada área ou atividade da

aplicação.

Angular usa o modo de routing HTML5. Em HTML5 é possível criar programaticamente novas

entradas da história do browser que mudam o URL mostrado, sem fazer um novo pedido ao

servidor. Isto é possível através do método history.pushState.

Uma boa prática em Angular é criar um módulo top-level, separado, dedicado ao routing e

importado pelo módulo raiz AppModule.

Assim, para adicionar Routing a uma aplicação Angular já existente, devemos usar o seguinte

comando ng:

> ng generate module app-routing --flat --module=app

e fazer as modificações indicadas no tutorial tour-of-heroes (toh).

É mais simples criar uma nova aplicação Angular com Routing usando o seguinte comando ng:

> ng new AngularRouting --routing

Neste caso não é necessário fazer qualquer modificação.

Ficheiro app.module.ts:

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

@NgModule({

declarations: [

AppComponent

Page 2: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

],

imports: [

BrowserModule,

AppRoutingModule

],

providers: [],

bootstrap: [AppComponent]

})

export class AppModule { }

Ficheiro app.component.html:

<!--The content below is only a placeholder and can be replaced.-->

<div style="text-align:center">

<h1>

<img width="50" src="data:image/svg+xml;base64,PHN2ZyB4bW . . . ZnPg==">

Welcome to {{title}}

</h1>

</div>

<router-outlet></router-outlet>

Ficheiro app-routing.module.ts:

import { NgModule } from '@angular/core';

import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule { }

No array routes vamos definir as rotas para a nossa aplicação e o método

RouterModule.forRoot(routes) configura essas rotas.

Quando mudamos de rota geralmente pretendemos manter uma parte do layout e só

substituir uma secção interior com o componente dessa rota. Para indicar o local onde

renderizar o conteúdo de cada rota usamos o elemento router-outlet.

1. Criação de Rotas

Vamos criar 3 componentes: “Area1”, “Area2” e “Area3”.

Na página template do componente raiz da aplicação (app.component.html) vamos colocar 3

links: Área1, Área2 e Área3.

Cada link muda a página para o template do respetivo componente.

> ng generate component Area1

> ng generate component Area2

> ng generate component Area3

Page 3: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

src/app/area1/area1.component.html: <h1> Área 1 works! </h1>

src/app/area2/area2.component.html: <h1> Área 2 works! </h1>

src/app/area3/area3.component.html: <h1> Área 3 works! </h1>

No ficheiro app-routing.module.ts definimos as rotas da aplicação.

Cada rota contém um path e um componente associado.

Ficheiro app-routing.module.ts:

import { NgModule } from '@angular/core';

import { Routes, RouterModule } from '@angular/router';

import { Area1Component } from './area1/area1.component';

import { Area2Component } from './area2/area2.component';

import { Area3Component } from './area3/area3.component';

const routes: Routes = [

{ path: 'area1', component: Area1Component },

{ path: 'area2', component: Area2Component },

{ path: 'area3', component: Area3Component },

]

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule { }

Para Angular navegar para uma dada rota o uso de um link HTML, como:

<div><a href = "/area1">Área 1</a></div>

desencadeia o reload da página, o que não é pretendido em SPAs.

A diretiva RouterLink (atributo routerLink) permite criar links para rotas sem fazer o reload da

página.

A diretiva RouterOutlet (elemento router-outlet) indica onde o componente de cada rota será

renderizado.

Ficheiro app.component.html:

<!--The content below is only a placeholder and can be replaced.-->

<div style="text-align:center">

<h1>

<img width="50" src="data:image/svg+xml;base64,PHN2ZyB4bW . . . ZnPg==">

Welcome to {{title}}

</h1>

</div>

<h3> AppComponent Router Links: &nbsp;&nbsp;&nbsp;

<a routerLink = "area1"> Área 1 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area2"> Área 2 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area3"> Área 3 </a> &nbsp;&nbsp;&nbsp;

</h3>

<h6> AppComponent Router Views (router-outlet): </h6>

<router-outlet></router-outlet>

Page 4: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

2. Definição de Rotas Children (Nested Routes)

Quando algumas rotas só são acessíveis e vistas dentro de outras rotas é apropriado criá-las

como rotas children.

Cada área da nossa aplicação pode ter os seus próprios componentes filho, que também têm o

seu próprio routre-outlet.

Vamos considerar que era apropriado executar certas atividades nas áreas seguintes:

• na Área1 as atividades: Atividade1, Atividade2 e Atividade3.

• na Área2 as atividades: Atividade1 e Atividade4.

• na Área3 as atividades: Atividade5 e Atividade2.

Criação dos componentes para as atividades:

> ng generate component Atividade1

> ng generate component Atividade2

> ng generate component Atividade3

> ng generate component Atividade4

> ng generate component Atividade5

src/app/atividade1/atividade1.component.html: <h1> Atividade 1 works! </h1>

src/app/atividade2/atividade2.component.html: <h1> Atividade 2 works! </h1>

src/app/atividade3/atividade3.component.html: <h1> Atividade 3 works! </h1>

src/app/atividade4/atividade4.component.html: <h1> Atividade 4 works! </h1>

src/app/atividade5/atividade5.component.html: <h1> Atividade 5 works! </h1>

Alteração do ficheiro app-routing.module.ts

import { NgModule } from '@angular/core';

import { Routes, RouterModule } from '@angular/router';

import { Area1Component } from './area1/area1.component';

import { Area2Component } from './area2/area2.component';

import { Area3Component } from './area3/area3.component';

import { Atividade1Component } from './atividade1/atividade1.component';

import { Atividade2Component } from './atividade2/atividade2.component';

import { Atividade3Component } from './atividade3/atividade3.component';

import { Atividade4Component } from './atividade4/atividade4.component';

import { Atividade5Component } from './atividade5/atividade5.component';

const routes: Routes = [

{ path:'area1', component: Area1Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade2', component: Atividade2Component },

{ path:'atividade3', component: Atividade3Component },

] },

{ path:'area2', component: Area2Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade4', component: Atividade4Component },

] },

{ path:'area3', component: Area3Component,

Page 5: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

children: [

{ path:'atividade5', component: Atividade5Component },

{ path:'atividade2', component: Atividade2Component },

] },

];

@NgModule({

imports: [RouterModule.forRoot(routes)],

exports: [RouterModule]

})

export class AppRoutingModule { }

Alteração do ficheiro area1.component.html

<h3>Area1 Router Links: &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade1"> Atividade 1 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade2"> Atividade 2 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade3"> Atividade 3 </a> &nbsp;&nbsp;&nbsp;

</h3>

<h1>

Área 1 works!

</h1>

<h6>Area1 Router Views (router-outlet):</h6>

<router-outlet></router-outlet>

É neste elemento router-outlet que serão renderizados os componentes associados às rotas

children: area1/atividade1, area1/atividade2, area1/atividade3.

Alteração do ficheiro area2.component.html

<h3>Area2 Router Links: &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade1"> Atividade 1 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade4"> Atividade 4 </a> &nbsp;&nbsp;&nbsp;

</h3>

<h1>

Área 2 works!

</h1>

<h6>Area2 Router Views (router-outlet):</h6>

<router-outlet></router-outlet>

Alteração do ficheiro area3.component.html

<h3>Area3 Router Links: &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade5"> Atividade 5 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "atividade2"> Atividade 2 </a> &nbsp;&nbsp;&nbsp;

</h3>

<h1>

Área 3 works!

</h1>

<h6>Area3 Router Views (router-outlet):</h6>

<router-outlet></router-outlet>

Page 6: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

3. Route Parameters

Para navegar para um recurso específico, usando por exemplo o URL /produtos/5 temos de

usar route parameters.

Para especificar que uma rota recebe um parâmetro colocamos : em frente ao path do

segmento, como:

/rota/:param

Page 7: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Para usar route parameters e obter o parâmetro para uma dada rota é necessário importar

ActivatedRoute, que tem informação acerca da rota ativa.

Criar os componentes Produtos e Produto:

> ng generate component Produtos

> ng generate component Produto

As alterações ao ficheiro app.module.ts são feitas automaticamente pelo scaffolding do

comando ng - acrescentados 2 imports e 2 declarations (ProdutosComponent e

ProdutoComponent).

Alterações ao ficheiro app-routing.module.ts:

import { ProdutosComponent } from './produtos/produtos.component';

import { ProdutoComponent } from './produto/produto.component';

const routes: Routes = [

{ path:'area1', component: Area1Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade2', component: Atividade2Component },

{ path:'atividade3', component: Atividade3Component },

]

},

{ path:'area2', component: Area2Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade4', component: Atividade4Component },

]

},

{ path:'area3', component: Area3Component,

children: [

{ path:'atividade5', component: Atividade5Component },

{ path:'atividade2', component: Atividade2Component },

]

},

{ path:'produtos', component: ProdutosComponent,

children: [

{ path:':id', component: ProdutoComponent },

]

},

];

Alterações ao ficheiro app.component.html:

<!--The content below is only a placeholder and can be replaced.-->

<div style="text-align:center">

<h1>

<img width="50" src="data:image/svg+xml;base64,PHN2Zy . . . vc3ZnPg==">

Welcome to {{title}}

</h1>

</div>

<h3> AppComponent Router Links: &nbsp;&nbsp;&nbsp;

Page 8: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

<a routerLink = "area1"> Área 1 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area2"> Área 2 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area3"> Área 3 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "produtos"> Produtos </a> &nbsp;&nbsp;&nbsp;

</h3>

<h6> AppComponent Router Views (router-outlet): </h6>

<router-outlet></router-outlet>

Injetar Router no construtor de ProdutosComponent para poder navegar programaticamente

para um route invocando a função navigate. O objeto Router injetado é mantido num campo

privado.

Ficheiro produtos.component.ts:

import { Component, OnInit } from '@angular/core';

import { Router } from '@angular/router';

@Component({

selector: 'app-produtos',

templateUrl: './produtos.component.html',

styleUrls: ['./produtos.component.css']

})

export class ProdutosComponent implements OnInit {

constructor(private router: Router) { }

mostrarProduto(id: string): void {

this.router.navigate(['/produtos', id]);

}

ngOnInit() {

}

}

Ficheiro produtos.component.html:

<h3>Produtos Router Links: &nbsp;&nbsp;&nbsp;

Id do Produto: <input #varId size="6">

<button (click) = "mostrarProduto(varId.value)"> Mostrar Produto </button>

</h3>

<h6>Produtos Router Views (router-outlet):</h6>

<router-outlet></router-outlet>

varId é uma variável referência template.

Variáveis referência template (template reference variables) são variáveis que referenciam um

elemento DOM, uma instância de um componente ou uma diretiva. O âmbito de validade

(scope) de uma variável template é todo o template. São definidas escrevendo o sinal hash (#)

junto com o nome, como um atributo adicional ao elemento DOM.

varId é um objeto do tipo HTMLInputElement que representa o elemento DOM Input. O objeto

DOM Input tem uma propriedade “value”, do tipo string, com o valor entrado pelo utilizador.

Page 9: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Injetar ActivatedRoute no construtor de ProdutoComponent para poder obter o parâmetro de

uma dada rota.

Ficheiro produto.component.ts:

import { Component, OnInit } from '@angular/core';

import { ActivatedRoute } from '@angular/router';

@Component({

selector: 'app-produto',

templateUrl: './produto.component.html',

styleUrls: ['./produto.component.css']

})

export class ProdutoComponent implements OnInit {

id: number;

constructor(private route:ActivatedRoute) {

this.id = +this.route.snapshot.paramMap.get('id');

}

ngOnInit() {

}

}

route.snapshot é uma imagem estática da rota após o componente ser criado.

paramMap é um dicionário com os valores dos parâmetros da rota extraídos do URL.

O operador JavaScript + converte string para number.

Ficheiro produto.component.html:

<h1>

Detalhes do Produto com Id = {{ id }}

</h1>

Executando a aplicação, http://localhost:4200

Alterar o URL do browser para http://localhost:4200/produtos/444

Page 10: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Clicar no link Produtos, preencher o campo de texto e clicar em Mostrar Produto.

Ao premir o botão “Mostrar Produto” o URL do browser também é atualizado.

Mantendo a vista do “ProdutoComponent”, alterar o Id do Produto no campo de texto e

premir o botão “Mostrar Produto” não tem efeito. Este problema ocorre porque Angular

verifica que a navegação desencadeada é tratada pelo mesmo componente que já está visível

para o utilizador e por isso não cria uma nova instância deste componente (por motivos de

eficiência). Quando este componente foi criado, recebeu o objeto ActivatedRoute, usado por

Page 11: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Angular para conter os detalhes da rota corrente, mas só foi usada a sua propriedade

snapshot, imagem estática da rota após o componente ser criado.

O método navigate() invocado por mostrarProduto() atualizou o objeto ActivatedRoute, e este

objeto tem propriedades que permitem partes interessadas receber notificações.

Alteração do ficheiro produto.component.ts:

import { Component, OnInit } from '@angular/core';

import { ActivatedRoute } from '@angular/router';

@Component({

selector: 'app-produto',

templateUrl: './produto.component.html',

styleUrls: ['./produto.component.css']

})

export class ProdutoComponent implements OnInit {

id: number;

constructor(private route: ActivatedRoute) {

// this.id = +this.route.snapshot.paramMap.get('id');

route.params.subscribe(parametros => {

this.id = +parametros['id'];

});

}

ngOnInit() {

}

}

Verificar que mantendo a vista do “ProdutoComponent”, ao alterar o Id do Produto no campo

de texto e premir o botão “Mostrar Produto” a vista do componente Produto é atualizada.

Page 12: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

4. Protected Route

Vamos considerar que pretendemos ter uma rota protegida, por exemplo só permitir a

aplicação ir para /produtos se o utilizador está autenticado.

O router deve ser notificado quando a rota protegida for ativada. Nessa altura o serviço de

autenticação deve ser invocado para determinar se o utilizador está autenticado.

Para verificar se um componente pode ser ativado adicionamos uma classe Guard à chave

canActivate na configuração do router.

Vamos criar um serviço muito simples para autenticação e autorização de recursos.

>ng generate service Auth

Ficheiro auth.service.ts

import { Injectable } from '@angular/core';

@Injectable()

export class AuthService {

constructor() { }

login(userName: string, password: string): boolean {

if (userName === 'user' && password === 'password') {

localStorage.setItem('userName', userName);

return true;

}

return false;

}

logout(): any {

localStorage.removeItem('userName');

}

getUser(): any {

return localStorage.getItem('userName');

}

isLoggedIn(): boolean {

return this.getUser() !== null;

}

}

Em HTML5 localStorage permite persistir informação no browser. A existência do item

“userName” em localStorage servirá como uma flag para indicar se existe um utilizador

autenticado.

Para poder injetar o serviço AuthService nos componentes que iremos criar temos de fornecer

(provide) este serviço no sistema de injeção de dependências.

Page 13: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Alteração do ficheiro app.module.ts (providers):

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

import { Area1Component } from './area1/area1.component';

import { Area2Component } from './area2/area2.component';

import { Area3Component } from './area3/area3.component';

import { Atividade1Component } from './atividade1/atividade1.component';

import { Atividade2Component } from './atividade2/atividade2.component';

import { Atividade3Component } from './atividade3/atividade3.component';

import { Atividade4Component } from './atividade4/atividade4.component';

import { Atividade5Component } from './atividade5/atividade5.component';

import { ProdutosComponent } from './produtos/produtos.component';

import { ProdutoComponent } from './produto/produto.component';

import { AuthService } from './auth.service';

@NgModule({

declarations: [

AppComponent,

Area1Component,

Area2Component,

Area3Component,

Atividade1Component,

Atividade2Component,

Atividade3Component,

Atividade4Component,

Atividade5Component,

ProdutosComponent,

ProdutoComponent

],

imports: [

BrowserModule,

AppRoutingModule

],

providers: [AuthService],

bootstrap: [AppComponent]

})

export class AppModule { }

Criação do componente Login com um formulário.

>ng generate component Login

Ficheiro login.component.ts:

import { Component, OnInit } from '@angular/core';

import { AuthService } from '../auth.service';

@Component({

selector: 'app-login',

templateUrl: './login.component.html',

styleUrls: ['./login.component.css']

})

export class LoginComponent implements OnInit {

message: string;

constructor(public authService: AuthService) {

this.message = '';

}

Page 14: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

ngOnInit() {

}

login(userName: string, password: string): boolean {

this.message = '';

if (!this.authService.login(userName, password)) {

this.message = 'Credenciais Incorretas.';

setTimeout(function() {

this.message = '';

}.bind(this), 2000);

}

return false;

}

logout(): boolean {

this.authService.logout();

return false;

}

}

A função login(userName, password) será invocada pelo formulário:

• Se o serviço de autenticação (AuthService) validar a autenticação, este serviço guarda o userName no localStorage.

• Se o serviço de autenticação não validar a autenticação, a mensagem “Credenciais Incorretas” é mostrada durante 2 segundos.

A função bind é usada para ligar (bind) o contexto corrente (this) à função, mesmo que seja executada mais tarde. As funções login e logout retornam false para o browser não recarregar a página.

Ficheiro login.component.html:

<h1>Login</h1>

<form *ngIf="!authService.getUser()">

<label for="username">User: (<em>user</em>)</label>

<input name="username" #username>

<label for="password">Password: (<em>password</em>)</label>

<input type="password" name="password" #password>

<button (click)="login(username.value, password.value)"> Submit </button>

</form>

<h3 class="erro" *ngIf="message"> {{ message }} </h3>

<div *ngIf="authService.getUser()">

Logged in as <b>{{ authService.getUser() }}</b>

<br/>

<button (click)="logout()">Log out</button>

</div>

Ficheiro login.component.css:

.erro {

color: red;

}

Page 15: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Criação da rota “login” em app-routing.module.ts e do link “Login” em app.component.html

Alterações ao ficheiro app-routing.module.ts:

import { LoginComponent } from './login/login.component';

const routes: Routes = [

{ path:'area1', component: Area1Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade2', component: Atividade2Component },

{ path:'atividade3', component: Atividade3Component },

]

},

{ path:'area2', component: Area2Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade4', component: Atividade4Component },

]

},

{ path:'area3', component: Area3Component,

children: [

{ path:'atividade5', component: Atividade5Component },

{ path:'atividade2', component: Atividade2Component },

]

},

{ path:'login', component: LoginComponent },

{ path:'produtos', component: ProdutosComponent,

children: [

{ path:':id', component: ProdutoComponent },

]

},

];

Alterações ao ficheiro app.component.html:

<!--The content below is only a placeholder and can be replaced.-->

<div style="text-align:center">

<h1>

<img width="50" src="data:image/svg+xml;base64,PHN2Zy . . . vc3ZnPg==">

Welcome to {{title}}

</h1>

</div>

<h3> AppComponent Router Links: &nbsp;&nbsp;&nbsp;

<a routerLink = "area1"> Área 1 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area2"> Área 2 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "area3"> Área 3 </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "produtos"> Produtos </a> &nbsp;&nbsp;&nbsp;

<a routerLink = "login"> Login </a> &nbsp;&nbsp;&nbsp;

</h3>

<h6> AppComponent Router Views (router-outlet): </h6>

<router-outlet></router-outlet>

Page 16: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Executar a aplicação, http://localhost:4200

Pretendemos que o componente Produtos só possa ser acedido por utilizadores autenticados.

Temos que criar uma classe guarda que implemente canActivate.

Page 17: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

> ng generate guard Auth

Ficheiro auth.guard.ts

import { Injectable } from '@angular/core';

import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from

'@angular/router';

import { Observable } from 'rxjs/Observable';

import { AuthService } from './auth.service';

@Injectable()

export class AuthGuard implements CanActivate {

constructor(private authService: AuthService) { }

canActivate(

next: ActivatedRouteSnapshot,

state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> |

boolean {

const isLoggedIn = this.authService.isLoggedIn();

console.log('canActivate', isLoggedIn);

return isLoggedIn;

}

}

Configuração do Router para usar esta guarda:

• Usar AuthGuard na configuração da rota “produtos”

• Incluir AuthGuard na lista de providers, para poder ser injetado

Alteração do ficheiro app-routing.module.ts:

import { AuthGuard } from './auth.guard';

const routes: Routes = [

{ path:'area1', component: Area1Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade2', component: Atividade2Component },

{ path:'atividade3', component: Atividade3Component },

]

},

{ path:'area2', component: Area2Component,

children: [

{ path:'atividade1', component: Atividade1Component },

{ path:'atividade4', component: Atividade4Component },

]

},

{ path:'area3', component: Area3Component,

children: [

{ path:'atividade5', component: Atividade5Component },

{ path:'atividade2', component: Atividade2Component },

]

},

{ path:'login', component: LoginComponent },

{ path:'produtos', component: ProdutosComponent,

canActivate: [AuthGuard],

children: [

{ path:':id', component: ProdutoComponent },

]

},

];

Page 18: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Alteração do ficheiro app.module.ts (providers):

import { BrowserModule } from '@angular/platform-browser';

import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';

import { Area1Component } from './area1/area1.component';

import { Area2Component } from './area2/area2.component';

import { Area3Component } from './area3/area3.component';

import { Atividade1Component } from './atividade1/atividade1.component';

import { Atividade2Component } from './atividade2/atividade2.component';

import { Atividade3Component } from './atividade3/atividade3.component';

import { Atividade4Component } from './atividade4/atividade4.component';

import { Atividade5Component } from './atividade5/atividade5.component';

import { ProdutosComponent } from './produtos/produtos.component';

import { ProdutoComponent } from './produto/produto.component';

import { AuthService } from './auth.service';

import { LoginComponent } from './login/login.component';

import { AuthGuard } from './auth.guard';

@NgModule({

declarations: [

AppComponent,

Area1Component,

Area2Component,

Area3Component,

Atividade1Component,

Atividade2Component,

Atividade3Component,

Atividade4Component,

Atividade5Component,

ProdutosComponent,

ProdutoComponent

],

imports: [

BrowserModule,

AppRoutingModule

],

providers: [ AuthService, AuthGuard ],

bootstrap: [AppComponent]

})

export class AppModule { }

Executar a aplicação, http://localhost:4200

Page 19: Angular Routing - dei.isep.ipp.ptmouta/ARQSI-2017-2018... · Angular Routing As aplicações Web tradicionais usam server-side routing: colocamos um URL num browser, que faz um pedido

Se o utilizador não estiver autenticado, clicar no link Produtos não tem efeito.

Após autenticação é possível aceder à área dos Produtos.