Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.

Prévia do material em texto

1.1
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
3.1
3.2
3.3
3.4
3.5
3.6
Tabela	de	conteúdos
Introdução
Conceitos	iniciais
Iniciando	com	o	Angular
Angular	CLI
Software	de	gerenciamento	escolar
Criando	o	projeto
Depurando	código	no	browser
Iniciando	com	teste	de	software
Apresentando	a	lista	de	disciplinas
Cadastrando	uma	disciplina
Excluindo	uma	disciplina
Editando	dados	de	uma	disciplina
Depurando	código	no	browser
Nível	intermediário
Interação	entre	componentes
Serviços
Acessando	dados	externos	de	forma	assíncrona
Acessando	dados	de	uma	API	HTTP
Rotas
Feature-modules
1
Desenvolvimento	web	front-end	com
Angular
Este	é	um	livro	open-source,	tanto	no	conteúdo	quanto	no	código-fonte	associado.	O
conteúdo	é	resultado	de	algumas	práticas	com	o	Framework	Angular	e	segue	uma
abordagem	prática,	com	foco	no	entendimento	de	conceitos	e	tecnologias	no	contexto	do
desenvolvimento	de	um	software	de	gerenciamento	escolar.
Com	o	passar	dos	capítulos	será	possível	perceber	a	utilização	iterativa	e	incremental	de
recursos	até	chegar	à	conclusão	do	desenvolvimento	do	gerenciador	escolar.
Parte	do	conteúdo	do	livro	é	baseada	na	documentação	oficial	do	Angular,	disponível	em
https://angular.io.
Como	o	Angular	é	um	projeto	em	constante	desenvolvimento	(pelo	menos	até	agora)	serão
publicadas	atualizações	no	conteúdo	do	livro	sempre	que	possível,	para	refletir	novos
recursos	e	funcionalidades.	No	momento,	o	conteúdo	do	livro	é	baseado	na	versão	5.2.0.
Conhecimentos	desejáveis
Este	livro	aborda	o	desenvolvimento	de	software	front-end	para	a	web	do	ponto-de-vista	do
Angular.	Isso	quer	dizer	que	não	trata	de	conceitos	iniciais	de	HTML,	CSS,	JavaScript,
TypeScript	e	Bootstrap.	Entretanto,	os	conceitos	fundamentais	dessas	tecnologias	vão
sendo	apresentados	no	decorrer	dos	capítulos,	conforme	surge	a	necessidade	deles.
Para	aprender	mais	sobre	essas	tecnologias	recomendo	essas	fontes:
TypeScript:	Documentação	oficial	do	TypeScript	-	Microsoft,	TypeScript	Deep	Dive
HTML,	CSS	e	JavaScript:	W3Schools
Boostrap:	Documentação	oficial	do	Bootstrap
Código-fonte
O	software	Angular	Escola,	que	serve	como	apoio	para	este	livro	está	disponível
gratuitamente	no	Github:	https://github.com/jacksongomesbr/angular-escola.	O	repositório
provê	branches	que	demonstram	a	evolução	do	desenvolvimento	do	software	na	mesma
ordem	dos	capítulos	do	livro.	Cada	capítulo,	se	necessário,	indica	qual	branch	utilizar.
Introdução
2
https://angular.io
https://www.typescriptlang.org/docs/home.html
https://www.gitbook.com/book/basarat/typescript/details
https://www.w3schools.com/
http://getbootstrap.com/docs/4.0/getting-started/introduction/
https://github.com/jacksongomesbr/angular-escola
Dependências
Para	utilizar	o	código-fonte	do	livro	e	desenvolver	em	Angular	você	precisa,	antes,	montar
seu	ambiente	de	desenvolvimento	com	algumas	ferramentas:
1.	 Git:	disponível	em	https://git-scm.com/
2.	 Node.js:	disponível	em	https://nodejs.org	representa	um	ambiente	de	execução	do
JavaScript	fora	do	browser	e	também	inclui	o	npm,	um	gerenciador	de	pacotes
3.	 Editor	de	textos	ou	IDE:	atualmente	há	muitas	opções,	mas	destaco	estas:
i.	 VisualStudioCode:	disponível	em	https://code.visualstudio.com/
ii.	 Nodepad++:	disponível	em	https://notepad-plus-plus.org/
iii.	 PHPStorm	ou	WebStorm:	disponíveis	em	https://www.jetbrains.com
Visão	geral
A	tabela	a	seguir	apresenta	uma	visão	geral	dos	conceitos	apresentados	ou	discutidos	em
cada	capítulo	do	livro.
Capítulo Conteúdos
Iniciando	com	o	Angular Arquitetura	do	Angular;	Elementos	da	Arquitetura	doAngular	(ex.:	módulos	e	componentes)
Angular	CLI Ferramenta	Angular	CLI;	Comandos
Criando	o	projeto Ferramenta	Angular	CLI;	Comando	new
Apresentando	a	lista	de
disciplinas Data	binding;	Diretivas;	Eventos
Cadastrando	uma	disciplina Formulários;	Two-way	Data	binding;	Eventos
Excluindo	uma	disciplina Two-way	Data	Binding;	Eventos
Editando	dados	de	uma
disciplina Formulários;	Two-way	Data	Binding;	Eventos
Melhorando	a	interface	gráfica
do	CRUD	de	disciplinas
Formulários;	Data	Binding;	Eventos;	Bootstrap;	Font
Awesome
Interação	entre	componentes Criação	de	componentes;	Input	e	Output	parainteração	entre	componentes
Introdução
3
https://git-scm.com/
https://nodejs.org
https://code.visualstudio.com/
https://notepad-plus-plus.org/
https://www.jetbrains.com
Iniciando	com	o	Angular
[info]	Objetivos	do	capítulo:
demonstrar	os	elementos	da	Arquitetura	do	Angular
demonstrar	a	relação	entre	os	elementos	da	Arquitetura	do	Angular	e	arquivos	do
projeto
Branch:	iniciando
O	Angular	é	um	framework	para	o	desenvolvimento	de	software	front-end.	Isso	quer	dizer
que	utiliza	tecnologias	padrão	do	contexto	web	como	HTML,	CSS	e	uma	linguagem	de
programação	como	JavaScript	ou	TypeScript.
Um	software	desenvolvido	em	Angular	é	composto	por	diversos	elementos	como:	módulos,
componentes,	templates	e	serviços.	Esses	elementos	fazem	parte	da	arquitetura	do
Angular,	que	é	ilustrada	pela	figura	a	seguir.
Essa	arquitetura	de	software	orientada	a	componentes	implementa	conceitos	de	dois
padrões	de	arquitetura	de	software:
MVC	(Model,	View,	Controller)	é	um	padrão	de	software	que	separa	a	representação	da
informação	(Model)	da	interação	do	usuário	com	ele	(View-Controller).	Geralmente,
Model	e	Controller	são	representados	por	código	em	linguagem	de	programação
(classes	e/ou	funções)	e	View	é	representado	por	HTML	e	CSS.
MVVM	(Model,	View,	View-Model)	é	um	padrão	de	software	semelhante	ao	MVC,	com
a	diferença	de	que	o	View-Model	utiliza	recurso	de	data	binding	(mais	sobre	isso
Iniciando	com	o	Angular
4
https://github.com/jacksongomesbr/angular-escola/tree/iniciando
depois)	para	fazer	com	que	a	View	seja	atualizada	automaticamente	quando	ocorrer
uma	modificação	no	Model.
No	contexto	do	Angular	esses	elementos	são	descritos	conforme	as	seções	a	seguir.
Elementos	da	Arquitetura	do	Angular
Módulos
Módulos	representam	a	forma	principal	de	modularização	de	código.	Isso	significa	que	um
módulo	é	um	elemento	de	mais	alto	nível	da	arquitetura	do	Angular	e	é	composto	por	outros
elementos,	como	componentes	e	serviços.
Um	software	desenvolvido	em	Angular	possui	pelo	menos	um	módulo,	chamado	root
module	(módulo	raiz).	Os	demais	módulos	são	chamados	feature	modules	(módulos	de
funcionalidades).
Bibliotecas
Bibliotecas	funcionam	como	um	agrupador	de	elementos	de	software	desenvolvido	em
Angular.	Bibliotecas	oficiais	têm	o	prefixo		@angular	.	Geralmente	é	possível	instalar
bibliotecas	utilizando	o	npm	(gerenciador	de	pacotes	do	NodeJs).
Uma	biblioteca	pode	conter	módulos,	componentes,	diretivas	e	serviços.
Componentes
Um	componente	está,	geralmente,	relacionado	a	algo	visual,	ou	seja,	uma	tela	ou	parte
dela.	Nesse	sentido,	um	componente	possui	código	(Controller)	que	determina	ou	controla
o	comportamento	da	interação	com	o	usuário	(View	ou	Template).
O	Template	determina	a	parte	visual	do	componente	e	é	definido	por	código	HTML	e	CSS,
além	de	recursos	específicos	do	Angular,	como	outros	componentes	e	diretivas.
Metadados
Metadados	são	um	recurso	do	Angular	para	adicionar	detalhes	a	classes.	Isso	é	utilizado
para	que	o	Angular	interprete	uma	classe	como	um	Módulo	ou	como	um	Componente,	por
exemplo.
Data	binding
Iniciando	com	o	Angular
5
Data	binding	(que	seria	algo	como	"vinculação	de	dados"	em	português)	é	um	reucrso	do
Angular	que	representa	um	componente	importante	da	sua	arquitetura.	Considere	os
seguintes	elementos:
um	Model	define	dados	que	serão	apresentados	no	Template
um	Template	apresenta	os	dados	do	Model
um	Controller	ou	um	View-Model	determina	o	comportamento	do	Template
Se	o	Controller	atualiza	o	Model,	então	o	Template	tem	que	ser	atualizado
automaticamente.	Se	o	usuário	atualiza	o	Model	por	meio	do	Template	(usando	um
formulário,	por	exemplo)	o	Controller	também	precisa	ter	acesso	ao	Model	atualizado.	O
Data	Binding	atua	garantindo	que	esse	processo	ocorra	dessa	forma.
Diretivas
Diretivas	representam	um	conceito	do	Angular	que	é	um	pouco	confuso.	Na	prática,	um
Componenteé	uma	Diretiva	com	um	Template.	Assim,	um	Componente	é	um	tipo	de
Diretiva,	que	nem	sempre	está	relacionada	a	algo	visual.	Angular	define	dois	tipos	de
diretivas:
Diretivas	Estruturais:	modificam	o	Template	dinamicamente	por	meio	de	manipulação
do	DOM	(Document	Object	Model),	adicionando	ou	removendo	elementos	HTML
Diretivas	de	Atributos:	também	modificam	o	Template,	mas	operam	sobre	elementos
HTML	já	existentes
Serviços
Um	Serviço	é	uma	abstração	do	Angular	utilizado	para	isolar	a	lógica	de	negócio	de
Componentes.	Na	prática,	um	Serviço	é	representado	por	uma	classe	com	métodos	que
podem	ser	utilizados	em	Componentes.	Para	isso,	para	que	um	Componente	utilize	um
serviço,	o	Angular	utiliza	o	conceito	de	Injeção	de	Dependência	(DI,	do	inglês
Dependency	Injection).	DI	é	um	padrão	de	software	que	faz	com	que	dependências	sejam
fornecidas	para	quem	precisar.	Na	prática,	o	Angular	identifica	as	dependências	de	um
Componente	e	cria	automaticamente	instâncias	delas,	para	que	sejam	utilizadas
posteriormente	no	Componente.
Enquanto	esses	elementos	da	Arquitetura	do	Angular	representam	conceitos,	é	importante
visualizar	a	relação	deles	com	elementos	práticos	do	software,	ou	seja,	código.	Para	isso,	a
seção	a	seguir	apresenta	a	estrutura	padrão	de	um	software	desenvolvido	em	Angular.
Iniciando	com	o	Angular
6
Estrutura	padrão	de	um	software	desenvolvido
em	Angular
Um	software	desenvolvido	em	Angular	é	representado	por	vários	arquivos	HTML,	CSS,
TypeScript	e	de	configuração	(geralmente	arquivos	em	formato	JSON).
+	src
		+	app
				-	app.component.css
				-	app.component.html
				-	app.component.ts
				-	app.module.ts
		+	assets
		+	environments
				-	environment.prod.ts
				-	environment.ts
		-	index.html
		-	maint.ts
		-	polyfills.ts
		-	styles.css
		-	tsconfig.app.json
		-	typings.d.ts
-	.angular-cli.json
-	package.json
-	tsconfig.json
-	tslint.json
No	diretório	raiz	do	software:
	src	:	contém	o	código-fonte	do	software	(módulos,	componentes	etc.)
	.angular-cli.json	:	contém	configurações	do	projeto	Angular	(nome,	scripts	etc.)
	package.json	:	contém	configurações	do	projeto	NodeJS	(um	projeto	Angular	utiliza
NodeJS	para	gerenciamento	de	pacotes	e	bibliotecas,	por	exemplo)
	tsconfig.json		e		tslint.json	:	contêm	configurações	do	processo	de	tradução	de
código	TypeScript	para	JavaScript
No	diretório		src	:
	app	:	contém	o	root	module	e	os	demais	feature	modules	do	projeto
	assets	:	contém	arquivos	CSS,	JSON	e	scripts,	por	exemplo
	environments	:	contém	arquivos	de	configuração	do	ambiente	de	desenvolvimento
(	environment.ts	)	e	de	produção	(	environment.prod.ts	)
	index.html	:	contém	o	código	HTML	inicial	para	o	projeto	e	inclui	o	componente
principal	do	root	module
	main.ts	:	contém	o	código	TypeScript	necessário	para	iniciar	o	software	(processo
Iniciando	com	o	Angular
7
chamado	de	Bootstrap)
	polyfills.ts	:	contém	código	TypeScript	que	indica	scripts	adicionais	a	serem
carregados	pelo	Browser	para	funcionamento	do	software	como	um	todo	e	para
questões	de	compatibilidade	com	versões	antigas	de	Browsers
	style.css	:	contém	o	código	CSS	para	definir	estilos	globais	para	o	software
	tsconfig.app.json		e		typings.d.ts	:	complementam	configurações	do	arquivo
	../tsconfig.json		específicas	para	o	software	em	questão
No	diretório		app	:
	app.component.css	,		app.component.html		e		app.component.ts	:	definem	o	component
AppComponent,	respectivamente:	apresentação	por	meio	de	CSS,	Template	e
Controller.	Basicamente,	estes	três	arquivos	formam	a	base	de	todo	componente
	app.module.ts	:	código	TypeScript	que	define	o	root	module
Esse	capítulo	incial	do	livro	apresentou	conceitos	importantes	do	Angular.	A	maior	parte	dos
conceitos	está	diretamente	relacionada	a	código-fonte	(HTML,	CSS,	TypeScript	e	JSON)
que	estão	em	arquivos	do	diretório	onde	encontra-se	o	projeto.
Sempre	que	necessário,	volte	a	esse	capítulo	para	revisar	conceitos	do	Angular.	Muito
provavelmente,	mesmo	desenvolvedores	experientes	precisem,	de	tempos	em	tempos,
rever	essas	definições	da	arquitetura	do	Angular.
Iniciando	com	o	Angular
8
Angular	CLI
[info]	Objetivos	do	capítulo:
apresentar	o	Angular	CLI
apresentar	comandos	para	criação	de	projetos,	módulos,	componentes	e	outros
elementos
apresentar	o	arquivo		.angular-cli.json	
O	Angular	CLI	(disponível	em	https://cli.angular.io)	é	uma	ferramenta	para	inicializar,
desenvolver,	criar	conteúdo	e	manter	software	desenvolvido	em	Angular.	A	principal
utilização	dessa	ferramenta	começa	na	criação	de	um	projeto.	Você	pode	fazer	isso
manualmente,	claro,	mas	lidar	com	todas	as	configurações	necessárias	para	o	seu	software
Angular	pode	não	ser	algo	fácil,	mesmo	se	você	for	um	desenvolvedor	com	nível	de
conhecimento	médio	a	avançado.
[info]	cê-éle-í?
Como	parte	do	vocabulário	do	Angular,	geralmente	é	interessante	pronunciar	angular
cê-ele-i,	isso	mesmo,	CLI	é	uma	sigla	para	Command	Line	Interface	(no	português
Interface	de	Linha	de	Comando).	Assim,	usar	"cli"	não	é	exclusividade	alguma	do
Angular	--	provavelmente	você	verá	isso	em	outros	projetos.
As	seções	a	seguir	vão	apresentar	como	instalar	e	utilizar	o	Angular	CLI	para	desenvolver
software	Angular.
Instalando
O	Angular	CLI	é	distribuído	como	um	pacote	do	NodeJS,	então	você	não	encontrará	um
instalador,	como	acontece	com	software	tradicional.	Ao	invés	disso,	você	precisa	de	um
ambiente	de	desenvolvimento	com	o	NodeJS	instalado	(esse	capítulo	não	trata	disso).
Depois	de	ter	o	NodeJS	instalado,	a	instalação	do	Angular	CLI	passa	pela	utilização	do
npm,	o	gerenciador	de	pacotes	do	NodeJS.	Para	isso,	a	seguinte	linha	de	comando	deve
ser	executada:
npm	install	-g	@angular/cli
Isso	fará	uma	instalação	global	do	Angular	CLI	(por	isso	o		-g		na	linha	de	comando)	e
disponibilizará	o	programa		ng	.
Angular	CLI
9
https://cli.angular.io
[warning]	Problemas	na	instalação?
Podem	acontecer	certos	problemas	na	instalação	do	Angular	CLI.	Por	exemplo,	você
pode	estar	com	uma	versão	bem	desatualizada	do	NodeJS	e	do	npm.	Assim,	garanta
sempre	que	seu	ambiente	de	desenvolvimento	esteja	com	as	versões	corretas	desses
programas.
Outra	situação	é	se	você	tiver	problemas	para	fazer	uma	instalação	global.	Se	for	o
caso,	faça	uma	instalação	local	(sem	o		-g		na	linha	de	comando)	e	execute	o
programa		ng		que	está	no	caminho		./node_modules/.bin/ng	.
Comandos
O	Angular	CLI	disponibiliza	uma	série	de	comandos,	que	são	fornecidos	como	parâmetros
para	o	programa	ng.	Além	disso,	cada	comando	possui	diversas	opções	(ou	flags).	Faça	o
exercício	de	se	acostumar	a	essas	opções	para	aumentar	a	sua	produtividade.
Os	principais	comandos	serão	apresentados	nas	seções	seguintes.
help
O	comando		help		é	muito	importante	porque	apresenta	uma	documentação	completa	do
Angular	CLI,	ou	seja,	todos	os	comandos	e	todas	as	suas	opções.
Exemplo:	documentação	completa
ng	help
Essa	linha	de	comando	apresenta	todos	os	comandos	e	todas	as	suas	opções.
Exemplo:	documentação	do	comando		new	:
ng	help	new
Essa	linha	de	comando	apresenta	apenas	as	opções	do	comando		new	.
As	opções	de	cada	comando	são	sempre	precedidas	de		--		(dois	traços).	Algumas	opções
aceitam	um	valor	e	geralmente	possuem	um	valor	padrão.
Exemplo:	comando	new	com	duas	opções
ng	new	escola-app	--skip-install	--routing	true	--minimal	true
Angular	CLI
10
Essa	linha	de	comando	fornece	três	opções	para	o	comando		new	:		--skip-install	,		--
routing		(que	recebe	o	valor		true	)	e		--minimal		(que	recebe	o	valor		true	).
new
O	comando		new		é	utilizado	para	criar	um	projeto	(um	software	Angular).	Exemplo:
ng	new	escola-app
Quando	a	linha	de	comando	do	exemplo	for	executada	será	criado	um	software	Angular
chamado	escola-app	e	estará	em	um	diretório	chamado		escola-app	,	localizado	a	partir	de
onde	a	linha	de	comando	estiver	sendo	executada.
A	parte	mais	interessante	de	criar	um	projeto	Angular	com	esse	comando	é	que	ele	cria
todos	os	arquivos	necessários	para	um	software	bastante	simples,	mas	funcional.
Para	cada	comando	do	Angular	CLI	é	possível	informar	opções.	Asopções	mais	usadas	do
comando		new		são:
	--skip-install	:	faz	com	que	as	dependências	não	sejam	instaladas
	--routing	:	se	for	seguida	de		true	,	o	comando	cria	um	módulo	de	rotas	(isso	será
visto	em	outro	capítulo
generate
O	comando		generate		é	utilizado	para	criar	elementos	em	um	projeto	existente.	Para
simplificar,	é	bom	que	o	Angular	CLI	seja	executado	a	partir	do	diretório	do	projeto	a	partir
de	agora.	Por	meio	desse	comando	é	possível	criar:
class
component
directive
enum
guard
interface
module
pipe
service
Como	acontece	com	outros	comandos,	o		generate		também	pode	ser	utilizado	por	meio	do
atalho		g	.
Exemplo:	criar	component	ListaDeDisciplinas
Angular	CLI
11
ng	generate	component	ListaDeDisciplinas
Essa	linha	de	comando	criará	o	diretório		./src/app/lista-de-disciplinas		e	outros	quatro
arquivos	nesse	mesmo	local:
	lista-de-disciplinas.component.css	
	lista-de-disciplinas.component.html	
	lista-de-disciplinas.component.spec.ts	
	lista-de-disciplinas.component.ts	
É	importante	notar	que	esses	arquivos	não	estão	vazios,	mas	já	contêm	código	que
mantém	o	software	funcional	e	utilizável.	Por	isso	o	Angular	CLI	considera	que	as	opções
(class,	component	etc.)	são	como	blueprints	(ou	plantas,	em	português).	Outra	coisa
importante	é	que	o	Angular	CLI	também	modificará	o	arquivo		./src/app/app.module.ts		se
necessário	(ou	outro	arquivo	que	represente	um	módulo	que	não	seja	o	root	module	--
mais	sobre	isso	depois).
serve
O	comando		serve		compila	o	projeto	e	inicia	um	servidor	web	local.	Por	padrão	o	servidor
web	executa	no	modo		--watch		,	que	reinicia	o	comando	novamente,	de	forma	incremental,
sempre	que	houver	uma	alteração	em	algum	arquivo	do	projeto,	e		--live-reload	,	que
recarrega	o	projeto	no	Browser	(se	houver	uma	janela	aberta)	sempre	que	houver	uma
mudança.
build
O	comando		build		compila	o	projeto,	mas	não	inicia	um	servidor	web	local.	Ao	invés	disso,
gera	os	arquivos	resultantes	da	compilação	em	um	diretório	indicado.
Veremos	mais	sobre	esses	e	outros	comando	no	decorrer	do	livro.
Angular	CLI
12
[info]	Espera,	compilação?
Como	já	disse,	você	pode	utilizar	JavaScript	ou	TypeScript	ao	desenvolver	projetos
Angular.	Isso	não	é	bem	assim.	Na	prática,	geralmente	você	encontrará	a
recomendação	(senão	uma	ordem)	de	utilizar	TypeScript.	O	problema	é	que	seu
Browser	não	entende	TypeScript,	por	isso	é	necessário	um	processo	de	tradução	do
código	TypeScript	para	JavaScript.	E	não	é	só	isso.	Há	vários	recursos	utilizados	no
projeto	Angular	criado	com	TypeScript	que	precisam	de	ajustes	para	que	funcionem	no
seu	Browser.
Por	isso	os	comandos		serve		e		build		são	tão	importantes	e	--	por	que	não	dizer?	--
browser-friendly	=)
Angular	CLI
13
Software	de	gerenciamento	escolar
[info]	Objetivo	do	capítulo:
apresentar	informações	sobre	gerenciamento	escolar
apresentar	requisitos	do	software	de	gerenciamento	escolar
Neste	livro	você	verá	informações	técnicas	sobre	desenvolvimento	de	software	web	com
Angular	e	isso	é	colocado	em	prática	por	meio	do	desenvolvimento	de	um	software	de
gerenciamento	escolar.	Antes	disso,	entretanto,	vamos	ao	contexto:	gerenciamento	escolar.
Contexto	da	escola
No	contexto	desse	livro	o	gerenciamento	escolar	é	aplicado	em	uma	escola	fictícia	com	as
seguintes	características:
a	estrutura	de	pessoal	(recursos	humanos)	tem	as	seguintes	características:
funcionários	são	pessoas	contratadas	para	ocupar	cargos	e	realizar	funções
um	funcionário	tem	um	cargo
um	funcionário	tem	uma	ou	mais	funções
um	funcionário	pode	ser:	administrativo	ou	docente
a	estrutura	acadêmica	da	escola	tem	as	seguintes	características:
há	três	níveis	de	ensino:	ensino	infantil,	ensino	fundamental,	ensino	médio
cada	nível	de	ensino	pode	ser	organizado	em	anos	de	ensino	e	cada	um	possui
disciplinas
a	relação	entre	nível	de	ensino	e	ano	de	ensino	é	chamada	de	estrutura	curricular,
cada	qual	com	disciplinas	e	suas	cargas	horárias	anuais
uma	turma	é	quando	um	item	do	componente	curricular	é	ministrado	durante	um
ano	letivo	e	tem	as	seguintes	características:
pode	ter	um	ou	mais	professores	por	disciplina
pode	ter	um	ou	mais	alunos
matrícula	é	quando	um	aluno	é	matriculado	em	uma	turma	e	cursa	todas
as	disciplinas	do	ano	letivo
fisicamente,	está	presente	em	uma	sala	de	aula	(sala	padrão)
uma	aula	é	quando	conteúdos	didáticos	de	uma	disciplina	da	turma	são
trabalhados	com	professores	e	alunos	em	horários	específicos	na	semana
uma	aula	pode	ter	participação	de	um	ou	mais	professores	[da	turma]
uma	aula	pode	ser	realizada	na	sala	de	aula	padrão	da	turma	ou	em
instalação	física
Software	de	gerenciamento	escolar
14
uma	aula	é	realizada	em	um	dia	da	semana,	em	um	horário	específico
(informação	utilizada	para	compor	a	grade	horária)
em	cada	aula	o	professor	registra	a	frequência	do	aluno	(presença	ou	falta)
cada	aula	tem	a	duração	de	50	minutos	e	conta	como	uma	hora	(na	Carga
Horária)
os	conteúdos	das	aulas	são	organizados	em	bimestres	e,	por	isso,	são	realizadas
avaliações	bimestrais,	totalizando	quatro	(para	cada	disciplina)	no	ano	letivo
ao	final	do	ano	letivo:
as	quatro	notas	são	utilizadas	para	compor	a	nota	final,	que	é	uma	média
aritmética	das	notas	dos	bimestres
o	aluno	é	considerado	"APROVADO"	na	disciplina	se	tiver	média	aritmética
igual	ou	superior	a	6,0	e	frequência	superior	a	75%
o	aluno	que	não	conseguir	nota	final	suficiente	pode	realizar	uma	prova	de
recuperação,	cuja	nota	substitui	a	nota	final.	Por	fim,	se	o	aluno	não	obtiver
nota	igual	ou	superior	a	6,0	na	recuperação	ele	é	considerado	"REPROVADO"
em	situações	excepcionais	o	aluno	pode	ser	considerado	"APROVADO"	em
conselho	de	classe	(uma	reunião	realizada	ao	final	do	ano	letivo	com	os
professores)
com	exceção	do	ensino	infantil,	o	aluno	só	pode	ser	matriculado	no	ano	seguinte
se	tiver	sido	aprovado	em	todas	as	disciplinas	do	ano	corrente
a	estrutura	física	da	escola	tem	as	seguintes	características:
uma	instalação	física	pode	ser:	prédio,	sala	admnistrativa,	laboratório	ou	sala	de
aula
Para	ilustrar	esse	contexto,	alguns	exemplos	de	estruturas	curriculares:
Figura	2.3.1	-	Exemplo	de	estrutura	curricular	do	Ensino	Médio	-	1º	ao	5º	ano
Software	de	gerenciamento	escolar
15
Figura	2.3.2	-	Exemplo	de	estrutura	do	Ensino	Fundamental	-	6º	ao	9º	ano
Figura	2.3.3	-	Exemplo	de	Estrutura	curricular	do	Ensino	Médio
Software	de	gerenciamento	escolar
16
Figura	2.3.4	-	Exemplo	de	Estrutura	curricular	do	Ensino	Infantil
Gerenciamento	escolar
Com	base	nas	características	da	escola	usada	nesse	contexto,	o	software	de
gerenciamento	escolar	compreende	os	seguintes	requisitos	conforme	os	atores:
gerente	do	sistema
gerenciar	o	cadastro	de	usuários	e	permissões	de	acesso
gerente	administrativo
gerenciar	o	cadastro	de	cargos
gerenciar	o	cadastro	de	funções
gerenciar	o	cadastro	de	funcionários
gerenciar	o	cadastro	de	instalações	físicas
gerente	de	ensino
gerenciar	o	cadastro	de	disciplinas
gerenciar	o	cadastro	de	níveis	de	ensino
gerenciar	o	cadastro	de	estruturas	curriculares
gerenciar	o	cadastro	de	turmas	(bem	como	professores	nas	turmas	e	horários)
gerenciar	o	cadastro	de	alunos	(geral)
gerenciar	o	cadastro	de	matrículas	(alunos	nas	turmas)
registrar	aprovação	ou	reprovação	excepcional	em	conselho	de	classe
professor
ver	as	turmas	em	que	ministra	disciplinas
ver	os	alunos	das	turmas	em	que	ministra	disciplinas
ver	a	agenda	de	aula	das	turmas	em	que	ministra	disciplinas	(turmas,	disciplinas,
salas	de	aula,	dias	da	semana	e	horários	de	aula)
ver	a	agenda	de	aula	da	escola	(todas	as	turmas	do	ano	letivo)
gerenciar	o	cadastro	de	frequência	dos	alunos	(nas	suas	turmas	e	disciplinas)
Software	de	gerenciamento	escolar
17
gerenciar	as	notas	das	avaliações	bimestrais	dos	alunos	(nas	suas	turmas	e
disciplinas)
aluno	(e/ou	pais	ou	responsáveis)
ver	a	estrutura	curricular	do	nível	e	ano	de	ensino	em	que	está	matriculado
ver	a	estrutura	curricular	de	todos	os	níveis	e	anos	de	ensino
ver	a	agenda	de	aula	da	turma	em	que	está	matriculado	(disciplinas,	professores,
salas	de	aula,	dias	da	semana	e	horários	de	aula)ver	o	histórico	acadêmico	(notas	e	situação	final	para	as	turmas	cursadas)
Uma	descrição	mais	completa	dos	requisitos	pode	ser	encontrada	aqui:
http://200.199.229.99/reqman/projects/3/documentation.pdf.
Software	de	gerenciamento	escolar
18
http://200.199.229.99/reqman/projects/3/documentation.pdf
Criando	o	projeto
[info]	Objetivos	do	capítulo:
demonstrar	como	utilizar	o	Angular	CLI	para	criar	o	projeto	angular-escola
apresentar	os	requisitos	de	software	que	serão	implementados	no	capítulo
Branch:	iniciando
O	capítulo	Angular	CLI	apresentou	essa	ferramenta,	comandos	e	opções.	A	primeira
utilização	da	ferramenta	está	na	criação	do	projeto	com	o	comando:
ng	new	angular-escola
Isso	fará	com	que	seja	criado	um	diretório		angular-escola		no	local	onde	o	comando	foi
executado.	Como	já	informado,	o	diretório	contém	código-fonte	de	um	software	Angular
funcional.	Para	vê-lo	em	execução	acesse	o	diretório		angular-escola		e	execute	o
comando:
npm	start
Esse	script	executa	o	comando		ng	serve		do	Angular	CLI	e	cria	um	servidor	web	local,	por
padrão	na	porta	4200.	Para	ver	o	software	em	funcionamento,	abra	o	endereço
	http://localhost:4200		no	seu	browser	de	preferência.	Mais	para	frente	podemos	discutir
um	pouco	mais	a	saída	desse	comando,	porque	é	muito	interessante.	O	resultado	deverá
ser	semelhante	ao	da	figura	a	seguir.
Criando	o	projeto
19
https://github.com/jacksongomesbr/angular-escola/tree/iniciando
Figura	2.4.1	-	Versão	inicial	do	software	em	execução	no	Browser
Esse	não	é	um	comando	do	Angular	CLI.	Antes,	é	um	comando	(script)	que	está	definido	no
arquivo		package.json	.
O	arquivo	package.json
O	arquivo		package.json		contém	informações	do	projeto,	scripts	e	dependências.	O	arquivo
criado	pelo	Angular	CLI	tem	mais	ou	menos	o	seguinte	conteúdo:
Criando	o	projeto
20
{
		"name":	"angular-escola",
		...
		"scripts":	{
				"ng":	"ng",
				"start":	"ng	serve",
				"build":	"ng	build	--prod",
				...
		},
		"private":	true,
		"dependencies":	{
				"@angular/animations":	"^5.2.0",
				"@angular/common":	"^5.2.0",
				"@angular/compiler":	"^5.2.0",
				"@angular/core":	"^5.2.0",
				"@angular/forms":	"^5.2.0",
				"@angular/http":	"^5.2.0",
				"@angular/platform-browser":	"^5.2.0",
				"@angular/platform-browser-dynamic":	"^5.2.0",
				"@angular/router":	"^5.2.0",
				"core-js":	"^2.4.1",
				"rxjs":	"^5.5.6",
				"zone.js":	"^0.8.19"
		},
		"devDependencies":	{
				"@angular/cli":	"1.6.6",
				"@angular/compiler-cli":	"^5.2.0",
				"@angular/language-service":	"^5.2.0",
				...
		}
}
Por	ser	um	conteúdo	em	formato	JSON,	o	interpretamos	da	seguinte	forma:
	name	:	é	o	atributo	que	define	o	nome	do	projeto	para	o	NodeJS	(nesse	ponto,	não	tem
a	ver	com	o	Angular)
	scripts	:	é	o	atributo	que	contém	scripts	que	podem	ser	executados	no	prompt
(exemplos:		npm	start		e		npm	run	build	).	Nesse	caso	esses	scripts	usam	o	Angular
CLI	(veja	os	valores	dos	atributos		start		e		build	)
	dependencies	:	é	o	atributo	que	define	as	dependências	do	projeto.	Basicamente,	as
dependências	atuais	são	padrão	para	software	desenvolvido	em	Angular.	Importante
notar	que	o	nome	de	cada	atributo	determina	o	pacote	(como		@angular/core	)	e	seu
valor	determina	a	versão	(como	 	̂ 5.2.0	,	indicando	a	versão	desses	pacotes	do
Angular)
	devDependencies	:	é	o	atributo	que	define	as	dependências	de	desenvolvimeto.	São
ferramentas	que	não	geram	código-fonte	que	será	distribuído	junto	com	o	software	que
está	sendo	desenvolvido
Criando	o	projeto
21
Examinando	o	código-fonte#0
Agora	que	você	já	conhece	um	pouco	mais	da	estrutura	do	software	Angular,	do	Angular
CLI	e	do	npm,	vamos	dar	uma	olhada	no	código-fonte	que	está	gerando	o	software	atual,
começando	pelo		AppComponent		e	seu	Template,	que	está	no	arquivo
	./src/app/app.component.html	,	cujo	trecho	de	conteúdo	é	apresentado	a	seguir.
<div	style="text-align:center">
		<h1>
				Welcome	to	{{	title	}}!
		</h1>
		<img	width="300"	alt="Angular	Logo"	src="data:image/svg+xml;base64,PHN...Pg==">
</div>
...
Se	HTML	for	familiar	pra	você	então	não	há	problema	para	entender	o	código	do	Template.
Na	verdade,	tem	algo	diferente	ali	perto	de		Welcome	to		e	vamos	falar	disso	daqui	a	pouco.
Agora,	o	Controller	do	mesmo	componente,	no	arquivo		./src/app/app.component.ts	,	com
código-fonte	a	seguir:
import	{	Component	}	from	'@angular/core';
@Component({
		selector:	'app-root',
		templateUrl:	'./app.component.html',
		styleUrls:	['./app.component.css']
})
export	class	AppComponent	{
		title	=	'app';
}
Há	pouco	conteúdo,	mas	já	são	usados	vários	conceitos	do	Angular,	vamos	examinar	um-a-
um:
1.	 a	primeira	linha	usa	a	instrução		import		para	incluir	algo	chamado		Component		e	que	é
disponibilizado	pelo	pacote		@angular/core	.
2.	 	Component		é	uma	annotation	function	e	é	utilizada	pelo	Angular	para	adicionar
metadados	à	classe		AppComponent	.
3.	 Os	metadados	são	fornecidos	como	parâmetro	para	a	função		Component	:
i.	 	selector	:	indica	que	o	seletor	é		app-root	.	E	o	que	é	seletor?	Veremos	daqui	a
pouco
ii.	 	templateUrl	:	indica	que	o	arquivo	utilizado	para	o	template	do	componente	é
	./app.component.html		(que	vimos	há	pouco)
Criando	o	projeto
22
iii.	 	styleUrls	:	é	um	array	que	indica	quais	são	os	arquivos	CSS	utilizados	no
componente.	Nesse	caso,	está	sendo	utilizado	apenas	o	arquivo
	./app.component.css	
4.	 a	instrução		export		é	utilizada	para	que	outros	arquivos	possam	utilizar	a	classe
	AppComponent	
Antes	de	prosseguirmos,	perceba	que	há	um	atributo	da	classe		AppComponent		chamado
	title		e	tem	o	valor		'app'		(onde	já	vimos	isso?).
A	figura	a	seguir	ilustra	a	estrutura	do		AppComponent	.
Figura	2.4.2	-	Estrutura	do	component	AppComponent
Como	mostra	a	figura	o	componente		AppComponent		é	composto	por	Template,	Controller	e
Model.	O	Template	está	definido	no	arquivo		./src/app/app.component.html	,	enquanto	o
Controller	e	o	Model	estão	definidos	no	arquivo		./src/app/app.component.ts	.	Template	e
Controller	são	mais	fáceis	de	identificar	nessa	arquitetura.	Enquanto	o	primeiro	está	no
arquivo	HTML	o	segundo	é	a	classe	no	arquivo	TypeScript.	Entretanto,	onde	está	o	Model?
Antes	de	responder	essa	pergunta	faça	um	alteração	no	Controller:	altere	o	valor	do	atributo
	title		para,	por	exemplo,		'Angular'	.
Se	você	não	tiver	interrompido	a	execução	do	script		npm	start		acontecerá	uma
recompilação	incremental	automaticamente	e	a	janela	do	Browser	será	recarregada.	Na
página,	o	que	está	logo	depois	de		Welcome	to		?	Isso	mesmo,	a	palavra	"Angular".	Que
mágica	é	essa?	Nenhuma	mágica!	Veja	novamente	o	Template,	mais	de	perto:
<h1>
Welcome	to	{{	title	}}!
</h1>
Criando	o	projeto
23
Nesse	momento	você	já	deve	ter	aprendido	que	o	trecho		{{	title	}}		é	responsável	por
fazer	com	que	o	valor	do	atributo		title		to	Controller	apareça	no	Browser.	Isso	é	resultado
do	processo	de	Data	binding:
analisa	o	Controller	e	identifica	métodos	e	atributos
interpreta	e	analisa	o	Template	e	procura	por,	por	exemplo,	conteúdo	que	esteja	entre
	{{		e		}}	
utiliza	o	recurso	de	interpolação,	que	faz	com	a	expressão	dentro	de		{{		e		}}		seja
interpretada	e	gere	uma	alteração	no	conteúdo	do	Template	ao	ser	apresentado	no
Browser.	Nesse	caso		{{	title	}}		significa:	mostre	o	valor	de		title	.
A	figura	a	seguir	ilustra	os	elementos	desse	processo.
Figura	2.4.3	-	Relação	entre	Model-Template-Controller	no	AppComponent
Aqui	aprendemos	algo	um	conceito	importante:	o	Angular	interpreta	o	Template.	Isso
significa	que	todo	o	seu	conteúdo,	HTML	e	CSS,	é	interpretado	pelo	Angular	antes	de	ser
entregue	para	o	Browser.	É	isso	que	faz	com	que	o	recurso	de	interpolação	funcione.	É	por
isso,	também,	que	Data	binding	é	tão	importante	no	Angular.	Ele	é	responsável	por	fazer
com	que	o	atributo		title	,	que	compõe	o	Model	(ah,	agora	sim!),	esteja	disponível	para	ser
usado	no	Template.	Além	disso,	qualquer	alteração	no	valor	desse	atributo	representará
uma	alteração	na	visualização	do	componente	no	Browser.
Se	você	se	lembrar	da	discussão	sobreAngular	ser	MVC	ou	MVVM	é	aqui	que	o
entendimento	pesa	a	favor	do	segundo.	O	Controller	não	está	desassociado	do	Model	e,
por	causa	do	Data	binding,	sua	função	inclui	informar	o	Template	de	que	ocorreu	uma
alteração	no	Model,	de	forma	que	ele	seja	atualizado.
Criando	o	projeto
24
É	isso,	o	Model	é	um	conceito	abstrato	e	está,	geralmente,	no	Controller,	representado	por
atributos	e	métodos	--	sim,	também	é	possível	mostrar	o	valor	retornado	por	um	método	no
template	(mais	sobre	isso	depois).
Para	finalizar	essa	seção	falta	entender	como	o		AppComponent		é	apresentado	e	qual	a
relação	dele	com	o		AppModule		ou	outros	componentes	do	projeto.	Para	isso,	veja	o	arquivo
	./src/index.html	:
<!doctype	html>
<html	lang="en">
<head>
		<meta	charset="utf-8">
		<title>Angular	Escola</title>
		<base	href="/">
		<meta	name="viewport"	content="width=device-width,	initial-scale=1">
		<link	rel="icon"	type="image/x-icon"	href="favicon.ico">
</head>
<body>
		<app-root></app-root>
</body>
</html>
Ele	é	o	primeiro	arquivo	que	o	Browser	acessa,	embora	não	somente	com	esse	conteúdo.
Quando	o	Angular	compila	o	código-fonte	ele	entrega	um	pouco	mais,	veja:
<!doctype	html>
<html	lang="en">
...
</head>
<body>
		<app-root></app-root>
		<script	type="text/javascript"	src="inline.bundle.js"></script>
		<script	type="text/javascript"	src="polyfills.bundle.js"></script>
		<script	type="text/javascript"	src="styles.bundle.js"></script>
		<script	type="text/javascript"	src="vendor.bundle.js"></script>
		<script	type="text/javascript"	src="main.bundle.js"></script>
</body>
</html>
Esse	é	um	trecho	do	código-fonte	visualizado	pelo	Browser.	Perceba	as	linhas	com
elementos		script		antes	da	tag		</body>	.	Esses	elementos	não	estão	no	código-fonte
original,	eles	foram	embutidos	aí	pelo	processo	de	compilação	do	Angular	(que	foi	iniciado
quando	o	script		npm	start		foi	executado).	Não	precisa	fazer	isso	agora	(sério!)	mas	em
algum	momento	você	vai	perceber	que	o	conteúdo	daqueles	arquivos	indicados	nos
elementos		script		é	realmente	muito	importante	porque	eles	representam	o	resultado	da
Criando	o	projeto
25
tradução	de	todo	o	código-fonte	do	projeto	em	conteúdo	que	o	Browser	consegue
interpretar.	Destaque	para	o	arquivo		main.bundle.js	,	que	contém	o	conteúdo	do	arquivo
	./src/main.ts		cujo	trecho	é:
import	{	enableProdMode	}	from	'@angular/core';
import	{	platformBrowserDynamic	}	from	'@angular/platform-browser-dynamic';
import	{	AppModule	}	from	'./app/app.module';
...
platformBrowserDynamic().bootstrapModule(AppModule)
		.catch(err	=>	console.log(err));
O	método		platformBrowserDynamic()		retorna	um	objeto	que	contém	o	método
	boostrapModule()		que,	ao	ser	executado,	recebe	como	parâmetro	a	classe		AppModule	,	que
será	utilizada	para	representar	o	root	module.	Lembra	disso?	No	capítulo	Iniciando	com	o
Angular	vimos	que	o	root	module	é	o	módulo	mais	importante	de	todo	projeto	Angular,
porque	é	o	primeiro	a	ser	executado	(agora	você	deve	estar	entendendo	isso).
Certo,	então	o	Angular	carrega	primeiro	o		index.html	,	depois	usa	o		AppModule		como	root
module,	mas	isso	ainda	não	explica	como	o		AppComponent		passou	a	aparecer	no	Browser.
Para	entender	isso,	veja	o	arquivo		./src/app/app.module.ts	,	que	define	o		AppModule	:
import	{	BrowserModule	}	from	'@angular/platform-browser';
import	{	NgModule	}	from	'@angular/core';
import	{	AppComponent	}	from	'./app.component';
@NgModule({
		declarations:	[
				AppComponent
		],
		imports:	[
				BrowserModule
		],
		providers:	[],
		bootstrap:	[AppComponent]
})
export	class	AppModule	{	}
As	três	primeiras	linhas	importam	os	módulos		BrowserModule		e		NgModule		dos	seus
respectivos	pacotes,	bem	como	a	classe		AppComponent	.	Como	você	já	sabe,	o	Angular
utiliza	annotation	functions	para	adicionar	metadados	a	classes.	Aqui	está	sendo	utilizada
a	função		NgModule()		que	transforma	a	classe		AppModule		em	um	módulo	para	o	Angular.	O
objeto	passado	como	parâmetro	para	a	função	possui	características	importantes	a
destacar:
	declarations	:	é	um	vetor	que	contém	componentes	do	módulo	(isso	mesmo,
Criando	o	projeto
26
	AppComponent		está	contido	no		AppModule	);
	imports	:	é	um	vetor	que	contém	as	dependências	(outros	módulos);
	bootstrap	:	é	um	vetor	que	contém	os	componentes	que	devem	ser	utilizados	quando
uma	instância	do		AppModule		passar	a	existir	(isso,	indicado	ali	no	arquivo
	./src/main.ts	).
As	coisas	estão	ficando	mais	conectadas	agora	e	a	figura	a	seguir	ilustra	isso.
É	isso!	O	elemento		app-root		é	interpretado	corretamente	pelo	Browser	quando	recebe	o
arquivo		index.html		porque	ele	está	indicado	como		selector		do		AppComponent	,	que	é	o
componente	executado	pelo		AppModule	,	qué	o	root	module.	O		selector		do		AppComponent	
é	utilizado	pelo	Angular	para	saber	onde	apresentar	o	component	no	Template.	O	valor
	'app-root'		indica	que	o	Angular	deve	procurar	um	elemento	com	esse	nome.	E	é	o	que
acontece.
Viu?	Não	é	mágica.	É	software!
O	que	vem	a	seguir?
Como	agora	você	já	deve	estar	entendendo	melhor	o	funcionamento	do	Angular	e	o	código-
fonte	do	projeto,	é	hora	de	sujar	as	mãos	=)	No	capítulo	a	seguir	você	vai	implementar	o
requisito:	ver	as	disciplinas.
Criando	o	projeto
27
Depurando	código	no	browser
[info]	Objetivos	do	capítulo:
demonstrar	como	utilizar	o	recurso	de	depuração	de	código	do	Browser
Branch:	iniciando
Devido	ao	processo	de	compilação/tradução	do	código-fonte	para	que	o	browser	execute	o
software	os	recursos	de	inspeção	do	código-fonte/elementos	apresenta	o	que	o	browser
interpreta,	ou	seja,	o	resultado	do	processo	de	compilação/tradução.	A	figura	a	seguir	ilustra
a	tela	de	um	browser	com	o	painel	das	ferramentas	de	desenvolvedor.
Enquanto	isso	é	útil	para	o	browser,	não	permite	que	o	desenvolver	possa	acompanhar	a
execução	de	partes	do	software	observando	o	código-fonte	original.
Entretanto,	a	mesma	ferramenta	dá	acesso	à	importante	funcionalidade	de	depuração	de
código.	Para	isso,	basta	acessar	o	painel	Sources	e,	na	aba	Network,	à	esquerda,	acessar
o	nó		webpack://		e	seu	filho	que	corresponde	ao	caminho	do	projeto	do	software	no
ambiente	local	(ex:		D:/developer/angular-escola	),	como	mostra	a	figura	a	seguir.
Depurando	código	no	browser
28
https://github.com/jacksongomesbr/angular-escola/tree/iniciando
A	figura	demonstra	que	o	arquivo		/src/app/app.component.ts		está	selecionado.	Do	lado
direito	da	lista	dos	arquivos	a	tela	apresenta	o	código-fonte	original	do	arquivo.	No	painel
que	mostra	o	código-fonte	há	um	breakpoint	(ponto	de	parada)	na	linha	9.	Isso	significa
que	a	execução	do	software	no	browser	terá	uma	pausa	quando	da	sua	execução.	Ainda
mais	à	direita	da	tela	há	uma	barra	de	ferramentas	que	permitem	controlar	a	depuração:
Os	botões	representam,	nesta	ordem:
pausar/continuar	a	execução	do	código
executar	a	próxima	linha	e	não	entrar	no	código	da	função/método
executar	a	próxima	linha	e	entrar	no	código	da	função/método
executar	a	próxima	linha	e	sair	do	código	da	função/método
desativar	os	breakpoints
pausar	em	exceções
A	figura	a	seguir	ilustra	a	tela	durante	o	processo	de	depuração.
Depurando	código	no	browser
29
Por	fim,	no	painel	mais	à	direita	é	possível	acessar	funcionalidades	como	inspecionar
variáveis	ou	expressões	(Watch),	ver	a	pilha	de	chamadas	(Call	stack)	e	inspecionar	as
variáveis	do	escopo	(Scope).
Depurando	código	no	browser
30
Iniciando	com	teste	de	software
[info]	Objetivos	do	capítulo:
apresentar	o	conceito	de	teste	de	software
demonstrar	como	escrever	testes	com	o	Angular	utilizando	Karma	e	Jasmine
Branch:	iniciando
Teste	de	software	é	uma	área	da	Engenharia	de	Software	que	envolve	um	conjunto	de
práticas	para	garantir	a	qualidade	de	software	conforme	requisitos	e	expectativas	dos
interessados,	clientes	ou	desenvolvedores.	Durante	esse	processo	há	geração	de
informação	e	conhecimento	que	permite	entender	o	comportamento	do	software	em
situações	simuladas	ou	com	dados	fictícios.
Uma	forma	de	avaliar	a	qualidade	do	software	utilizando	testede	software	é	utilizar
mecanismos	que	permitam	identificar	se	o	software	está	operando	como	esperado,	fazendo
o	que	deveria	fazer.
Ao	criar	o	projeto	com	o	Angular	CLI,	junto	com	o	componente		AppComponent		também	é
criado	o	arquivo		src/app/app.component.spec.ts	.	Esse	arquivo	TypeScript	descreve	testes
utilizando	Jasmine.	Por	definição	Jasmine	é	um	framework	de	teste	de	software	que	segue
a	técnica	BDD	(Behaviour	Driven	Development).	Embora	o	Jasmine	possa	ser	utilizado
diretamente	para	testar	JavaScript	o	Angular	utiliza	duas	outras	tecnologias:
Karma,	uma	ferramenta	utilizada	para	executar	os	testes	escritos	em	Jasmine	(por
definição,	Karma	é	um	test	runner);	e
Protractor,	um	framework	para	testes	end-to-end	(e2e).
Então,	um	trecho	do	arquivo		src/app/app.component.spec.ts	:
Iniciando	com	teste	de	software
31
https://github.com/jacksongomesbr/angular-escola/tree/iniciando
https://jasmine.github.io/index.html
https://karma-runner.github.io/1.0/index.html
http://www.protractortest.org
import	{	TestBed,	async	}	from	'@angular/core/testing';
import	{	AppComponent	}	from	'./app.component';
describe('AppComponent',	()	=>	{
		...
		}));
		it('should	create	the	app',	async(()	=>	{
		...
		}));
		it(`should	have	as	title	'Angular'`,	async(()	=>	{
		...
		}));
		it('should	render	title	in	a	h1	tag',	async(()	=>	{
		...
		}));
});
Testes	escritos	em	Jasmine	são	chamados	de	specs	e,	por	padrão,	precisam	estar	em
arquivos	com	nomes	que	terminem	em		.spec.ts		(isso	está	definido	no	arquivo
	src/tsconfig.spec.json	).
Depois	das	primeiras	linhas	com	import	há	a	primeira	utilização	de	um	recurso	do	Jasmine:
a	chamada	do	método		describe()	.	Esse	método	cria	uma	suíte	de	testes	(um	grupo	de
testes).	Os	parâmetros	para	o	método	são:
o	nome	da	suíte	de	testes;	e
uma	função	que	define	suítes	internas	e	specs.
No	exemplo,	o	nome	da	suíte	é	'AppComponent'	e	a	função	que	define	as	suítes	internas	e
as	specs	está	definindo	três	testes.
As	specs	(testes)	são	definidas	por	meio	de	uma	chamada	ao	método	it().	Esse	método	cria
uma	spec.	Os	parâmetros	do	método	são:
o	nome	da	spec	(na	prática,	uma	descrição	do	que	a	spec	está	testando);
uma	função	que	descreve	o	código	do	teste;	e
um	número	que	representa	o	tempo	limite	de	execução	do	teste	(timeout).
No	caso	do	exemplo	há	três	specs:
	should	create	the	app		(deveria	criar	o	app	--	ou	o	app	deveria	ser	criado)
	should	have	title	as	'Angular'		(deveria	ter	o	título	como	'Angular'	--	ou	o	título
deveria	ser	'Angular')
	should	render	title	in	a	h1	tag		(deveria	renderizar	o	título	em	uma	tag	h1	--	ou	o
título	deveria	estar	em	uma	tag	h1)
Iniciando	com	teste	de	software
32
Percebeu	o	"should"	(deveria)	no	nome	de	cada	spec?	Isso	faz	parte	da	filosofia	BDD	que
indica	que	cada	spec	checa	se	as	expectativas	sobre	o	teste	são	válidas	(passam)	ou	não
(falham).	Antes	de	ver	mais	detalhes,	vamos	testar	o	software.	Execute	o	comando:
npm	test
Esse	comando	executa	o	script	"test"	definido	no	arquivo		package.json	.	Na	prática,	ele
executa	o	comando		ng	test	.
Dentro	de	instantes	você	deveria	ver	uma	janela	do	browser	mostrando	algo	semelhante	ao
da	figura	a	seguir.
Figura	2.6.1	-	Janela	do	browser	demonstrando	o	resultado	dos	testes	iniciais
Note	que	a	URL	do	browser	é		http://localhost:9876	.	Essa	é	a	URL	padrão	que	apresenta
os	resultados	do	teste	do	software.	A	tela	apresenta	várias	informações	importantes:
versão	do	sistema	operacional	(Windows	10)
Iniciando	com	teste	de	software
33
versão	do	browser	(Chrome	63)
versão	do	Karma	(1.7.1)
versão	do	Jasmine	(2.6.4)
tempo	total	de	execução	dos	testes	(0.187s)
quantidade	de	specs	(3)
quantidade	de	falhas	é	zero	(0),	o	que	indica	que	todos	os	testes	passaram	(ou	que
não	houve	falha	nos	testes)
Além	disso	a	tela	apresenta	o	próprio	componente	(	AppComponent	)	em	execução.	Ainda,
também	há	informações	no	prompt.	Você	deveria	ver	algo	como	o	seguinte:
15	12	2017	01:56:31.937:WARN	[karma]:	No	captured	browser,	open	http://localhost:9876/
15	12	2017	01:56:32.381:INFO	[Chrome	63.0.3239	(Windows	10	0.0.0)]:	Connected	on	socke
t	...
Chrome	63.0.3239	(Windows	10	0.0.0):	Executed	0	of	3	SUCCESS	(0	secs	/	0	secs)
Chrome	63.0.3239	(Windows	10	0.0.0):	Executed	1	of	3	SUCCESS	(0	secs	/	0.101	secs)
Chrome	63.0.3239	(Windows	10	0.0.0):	Executed	2	of	3	SUCCESS	(0	secs	/	0.143	secs)
Chrome	63.0.3239	(Windows	10	0.0.0):	Executed	3	of	3	SUCCESS	(0	secs	/	0.184	secs)
Chrome	63.0.3239	(Windows	10	0.0.0):	Executed	3	of	3	SUCCESS	(0.092	secs	/	0.184	secs)
Essas	informações	indicam	dados	adicionais:
o	primeiro	teste	executou	em	0.101s
o	segundo	teste	executou	em	0.143	-	0.101	=	0.042s
o	terceiro	teste	executou	em	0.184	-	0.143	=	0.041s
Ok,	agora	vamos	a	detalhes	dos	testes	mas,	antes	de	ver	cada	teste	individualmente,	o
segundo	parâmetro	do	método		describe()		chama	o	método		beforeEach()	,	que	é	utilizada
para	realizar	uma	espécie	de	setup	dos	testes,	executando	um	código	antes	deles:
import	{	TestBed,	async	}	from	'@angular/core/testing';
import	{	AppComponent	}	from	'./app.component';
describe('AppComponent',	()	=>	{
		beforeEach(async(()	=>	{
				TestBed.configureTestingModule({
						declarations:	[
								AppComponent
						],
				}).compileComponents();
		}));
		...
A	classe		TestBed		é	um	utilitário	do	Angular	para	testes	de	software.	Seu	método
	configureTestingModule()		cria	um	módulo	específico	para	executar	os	testes	que	serão
descritos	a	seguir.	Pense	nisso	como	um	módulo	mais	enxuto	que	os	utilizados	no	restante
Iniciando	com	teste	de	software
34
do	software,	voltando	apenas	para	esses	testes.	Por	isso	você	deveria	entender	que	o
parâmetro	fornecido	para	o	método	é	muito	similar	aos	metadados	de	um	módulo	e,	nesse
caso,	indicam	os	componentes	do	módulo	(atributo		declarations	).	Portanto,	o	setup
permite	que	cada	teste	utilize	o	componente		AppComponent	.
Primeiro	teste
O	trecho	de	código	a	seguir	apresenta	o	primeiro	teste.
it('should	create	the	app',	async(()	=>	{
		const	fixture	=	TestBed.createComponent(AppComponent);
		const	app	=	fixture.debugElement.componentInstance;
		expect(app).toBeTruthy();
}));
Esse	primeiro	teste	verifica	se	foi	possível	criar	uma	instância	do	componente
	AppComponent	,	o	que	é	feito	por	meio	de	uma	sequência	de	passos:
1.	 criar	uma	instância	de		AppComponent	:	isso	é	feito	por	meio	do	método
	TestBed.createComponent()		(armazenado	na	variável		fixture	)	que	retorna	uma
instância	de		ComponentFixture	,	referência	ao	ambiente	de	execução	dos	testes.	O
ambiente	de	execução	dos	testes	dá	acesso	ao		DebugElement	,	que	representa	o
elemento	do	DOM	que	representa	o	componente
2.	 acessar	a	instância	do	componente	(	fixture.debugElement.componentInstance	),
armazenada	na	variável		app	;
3.	 criar	uma	expectativa	para	o	teste
Uma	expectativa	é	criada	por	meio	do	método		expect()	.	Uma	expectativa	representa	o
comportamento	esperado	do	software:	que		app		(uma	instância	do		AppComponent	)	não	seja
	null	.	O	parâmetro	de		expect()		indica	a	expressão	que	será	analisada,	comparada,	com
outra	expressão	ou	valor.	Nesse	caso	a	comparação	é	realizada	por	meio	do	método
	toBeTruthy()	.	Se	a	expectativa	não	for	satisfeita	o	teste	falhará.	Isso	seria	o
comportamento	obtido,	por	exemplo,	por	causa	de	um	erro	de	tempo	de	execução
(runtime).
Segundo	teste
O	trecho	de	código	a	seguir	apresenta	o	segundo	teste.
Iniciando	com	teste	de	software
35
it(`should	have	as	title	'Angular'`,	async(()	=>	{
		const	fixture	=	TestBed.createComponent(AppComponent);
		const	app	=	fixture.debugElement.componentInstance;
		expect(app.title).toEqual('Angular');
}));
A	sequência	de	passos	é	semelhante	à	do	primeiro	teste.	A	diferença	está	na	expectativa:	o
teste	deseja	verificar	se	o	atributo		title		da	instância	do		AppComponent		(	app	)	tem	valor
igual	a		'Angular'	.	Novamente,	a	expectativa	é	criada	por	meio	do	método		expect()	.
Dessa	vez	a	comparação	entre	o	valor	esperado	(	app.title	)	e	o	valor	obtido	(	'Angular'	)
é	feita	por	meio	do	método		toEqual().
Com	isso	aprendemos	que	é	possível	testar	membros	de	um	componente	(atributos	e
métodos),	o	que	é	muito	valioso.
Terceiro	teste
O	trecho	de	código	a	seguir	apresenta	o	terceiro	teste.
it('should	render	title	in	a	h1	tag',	async(()	=>	{
		const	fixture	=	TestBed.createComponent(AppComponent);
		fixture.detectChanges();
		const	compiled	=	fixture.debugElement.nativeElement;
		expect(compiled.querySelector('h1').textContent).toContain('Welcome	to	Angular!');
}));
Em	relação	aos	testes	anteriores	a	sequência	de	passos	inclui	uma	chamada	ao	método
	ComponentFixture.detectChanges()	.	Você	deveria	aprender,	nos	capítulos	seguintes,	que	o
Angular	utiliza,	muito,	um	recurso	chamado	data	binding.	Esse	recurso	faz	com	que	o	valor
do	atributo		title		seja	apresentado	no	Template.	Para	checar	se	esse	é	o	comportamento
obtido	é	necessário,	primeiro,	identificar	que	ocorreu	data	binding.	Uma	forma	de	fazer	isso
é	usando	o	método		detectChanges()	.
Outra	diferença	é	que	o	teste	lida	com	o	DOM	depois	de	ter	sido	transformado	pelo	Angular,
ou	seja,	na	prática,	em	como	o	usuário	está	vendo	o	componente	no	momento.	Por	causa
disso	não	é	utilizada	uma	instância	do	componente,	mas	uma	referência	ao	DOM	compilado
(o	elemento	DOM	na	raiz	do	componente,	na	verdade).	Isso	é	feito	por	meio	de
	fixture.debugElement.nativeElement		(armazenado	na	variável		compiled	).
Por	fim,	a	expectativa	é	um	pouco	mais	complexa,	pois	envolve	lidar	com	o	DOM.	Para	isso
ocorre	o	seguinte:
1.	 encontrar	o	elemento		h1		no	DOM:	isso	é	feito	por	meio	do	método		querySelector()	;
Iniciando	com	teste	de	software
36
2.	 comparar	o	conteúdo	textual	do	elemento		h1		com	a	string		Welcome	to	Angular!	:	isso
é	feito	por	meio	de	uma	expectativa	sobre	o	valor	do	atributo		textConent		do	objeto	que
representa	o	elemento		h1		conter	a	string	desejada,	comparação	implementada	pelo
método		toContain()	.
You	shall	not	pass!	Ou	provocando	uma	falha
nos	testes
Suponha	que	você	modifique	o	valor	do	atributo		title		do		AppComponent		para		'Web'	.	O
que	os	testes	diriam?	Se	os	testes	ainda	estiverem	em	execução,	apenas	observe	a	janela
do	browser	que	mostra	o	resultado	dos	testes	(ilustrada	pela	figura	a	seguir).
Iniciando	com	teste	de	software
37
A	saída	dos	testes	mostra	claramente	que	algo	errado	aconteceu:	dos	três	testes,	dois
falharam.	A	saída	indica	cada	teste	que	falhou	(detalhe	em	vermelho):
o	segundo	teste	falhou	porque	a	string		'Web'		não	igual	a		'Angular'	;	e
o	terceiro	teste	falhou	porque	a	string		'Welcome	to	Web!'		não	contém		'Welcome	to
Angular!'	.
Percebeu	que	os	testes	são	executados	novamente	sempre	que	há	uma	mudança	no
código	do	software?	Esse	é	o	comportamento	padrão,	mas	se	você	precisar	desligá-lo
precisará	de	uma	mudança	no	arquivo		package.json	,	modificando	o	script	de	teste	de	(	ng
test	):
...
"scripts":	{
...
		"test":	"ng	test",
...
},
...
para	(	ng	test	--single-run	):
...
"scripts":	{
...
		"test":	"ng	test	--single-run",
...
},
...
O	problema	disso	é	que,	ao	executar	o	comando		npm	test		você	verá	a	janela	do	browser
aparecer	e	sumir	logo	depois	de	alguns	instantes.	Assim,	precisará	lidar	com	a	saída	do
comando	no	prompt	para	identificar	o	que	ocorreu	(testes	passaram	ou	falharam).
Iniciando	com	teste	de	software
38
[info]	Resumo	do	capítulo:
testes	de	software	permitem	avaliar	se	o	comportamento	do	software	está	como	o
esperado
Jasmine	é	um	framework	utilizado	para	escrever	testes	usando	a	técnica	BDD
Karma	e	Protractor	são	ferramentas	do	Angular	para	executar	testes
o	comando		npm	test		é	usado	para	executar	testes
testes	são	definidos	dentro	de	suítes
uma	suíte	é	criada	usando	o	método		describe()	
um	teste	é	criado	usando	o	método		it()	
um	teste	pode	validar	diversos	comportamentos	do	software,	mas	cada
comportamento	é	validado	usando	o	método		expect()	,	que	compara	um	valor
esperado	com	um	valor	obtido
testes	do	Angular	envolvem	verificar	membros	do	componente	(atributos	e
método)	e	o	DOM	compilado,	que	é	visualizado	pelo	cliente	no	browser
Iniciando	com	teste	de	software
39
Apresentando	a	lista	de	disciplinas
[info]	Objetivos	do	capítulo:
demonstrar	a	implementação	do	requisito	"apresentar	as	disciplinas"	de	forma
iterativa
demonstrar	o	uso	das	diretivas		ngFor		e		ngIf	
reforçar	o	entendimento	do	Data	binding
Branches:	livro-listando-disciplinas,	livro-listando-disciplinas-objetos,	livro-listando-
disciplinas-classes,	livro-listando-disciplinas-interacao
Começando	pelo	Controller	do		AppComponent	,	remova	o	atributo		title		e	adicione	o
atributo		disciplinas	.	Esse	atributo	é	um	array	de	string,	contendo	os	nomes	das
disciplinas.	O	conteúdo	do	Controller	deve	ficar	mais	ou	menos	assim	(trecho):
export	class	AppComponent	{
		disciplinas	=	[
				'Língua	Portuguesa',
				'Arte',
				'Educação	Física',
				'Matemática',
				'História',
				'Geografia',
				'Ciências',
				'Redação',
				'Língua	Estrangeira	Moderna	-	Inglês',
				'Ensino	Religioso'
		];
}
Na	sequência	altere	o	Template	do		AppComponent		para	o	seguinte	conteúdo:
<h1>Disciplinas</h1>
<hr>
<ul>
		<li	*ngFor="let	disciplina	of	disciplinas">
				{{disciplina}}
		</li>
</ul>
Parte	importante	do	Template	está	no	elemento		li	:	o	atributo		*ngFor		é,	na	verdade,	uma
diretiva	estrutural	que	modifica	o	Template	no	browser,	gerando	novos	elementos	com
base	em	uma	repetição.
Apresentando	a	lista	de	disciplinas
40
https://github.com/jacksongomesbr/angular-escola/tree/livro-listando-disciplinas
https://github.com/jacksongomesbr/angular-escola/tree/livro-listando-disciplinas-objetos
https://github.com/jacksongomesbr/angular-escola/tree/livro-listando-disciplinas-classes
https://github.com/jacksongomesbr/angular-escola/tree/livro-listando-disciplinas-interacao
A	diretiva,	na	verdade	mesmo,	é	chamada		NgForOf	.	Usamos	uma	espécie	de	atalho
por	meio	do	atributo		*ngFor		(sem	mais	explicações	sobre	isso,	por	enquanto).	Então,
ao	ler		NgForOf		ou		*ngFor		saiba	que	estamos	falando	da	mesma	coisa.
A	diretiva		*ngFor		é	utilizada	para	repetir	um	elemento	do	Template.	Nesse	caso,	é
justamente	essa	a	sua	aplicação:	repetir	o	elemento		li		para	apresentar	os	nomes	das
disciplinas.	A	repetição	é	realizada	por	uma	expressão:		let	disciplina	of	disciplinas	
significa	que	o		*ngFor		vai	repetir	o	elemento		li		para	cada	item	do	array		disciplinas		e
cada	item	recebe	o	nome	de		disciplina	,	o	que	demonstra	outra	utilização	do	Data
binding.	Explicando	a	mesma	coisa	de	outra	forma:
a	repetição	sempre	é	baseada	em	uma	coleção	de	itens	(ou	em	algo	que	possa	ser
interpretado	como	tal)
o	Angular	cria	uma	variável	de	template	(existe	apenas	dentro	do	elemento		li	)	com	o
nome	de		disciplina	
essa	variável	de	template	é	usada	como	uma	referência	para	cada	item	da	repetição
É	por	isso	que	a	interpolação	funciona	dentro	do	elemento		li		para	apresentar	o	nome	de
cada	disciplina.
A	documentação	do	Angular	afirma	que		let	disciplina	of	disciplinas		é	uma
microssintaxe	e	isso	não	é	a	mesma	coisa	que	uma	expressão	usada	em	uma
interpolação.
Abra	o	aplicativo	no	browser.	O	resultado	deve	ser	semelhante	à	figura	a	seguir.
Apresentando	a	lista	de	disciplinas
41
Figura	2.7.1	-	Apresentando	a	lista	das	disciplinas
Melhorando	o	modelo	de	dados	usando
objetos
A	utilização	de	um	array	de	strings	pode	ser	suficiente	em	vários	casos.	Entretanto,	quando
se	deseja	apresentar	mais	informações	é	necessário	utilizar	outra	abordagem.	Suponha,
portanto,	que	precisemos	apresentar	dois	dados	de	cada	disciplina:	nome	e	descrição.
Uma	boa	forma	de	fazer	isso	é	utilizar	objetos.
Modifique	o	Controller	do		AppComponent		para	que	cada	item	do	array		disciplinas		seja	um
objeto	com	dois	atributos:		nome		e		descricao	,	como	mostra	o	trecho	de	código	a	seguir.
Apresentando	a	lista	de	disciplinas
42
...
export	class	AppComponent	{
		disciplinas	=	[
				{
						nome:	'Língua	Portuguesa',
						descricao:	'O	objetivo	norteador	da	BNCC	de	Língua	Portuguesa	é	'	+
						'garantir	a	todos	os	alunos	o	acesso	aos	saberes	'+
						'linguísticos	necessários	para	a	participação	social	e	o	exercício	'	+
						'da	cidadania,	pois	é	por	meio	da	língua	que	'	+
						'o	ser	humano	pensa,	comunica-se,	tem	acesso	à	informação,	expressa	'	+
						'e	defende	pontos	de	vista,	partilha	ou	'	+
						'constrói	visões	de	mundo	e	produz	conhecimento.'
				},
				...
		];
}
Essa	notação	do	TypeScript	para	representar	objetos	de	forma	literal	é	muito	útil	quando
não	se	tem	uma	classe	para	descrever	objetos.
Na	sequência	ocorre	uma	pequena	alteração	no	Template:
<h1>Disciplinas</h1>
<hr>
<ul>
		<li	*ngFor="let	disciplina	of	disciplinas">
						<strong>{{disciplina.nome}}</strong>:	{{disciplina.descricao}}
		</li>
</ul>
A	principal	mudança	está	no	fato	de	que	as	interpolações	usam	expressões	baseadas	nos
atributos	do	objeto		disciplina	.
Para	ver	o	resultado,	abra	o	aplicativo	no	browser.
Melhorando	o	modelo	de	dados	usando
classes
Enquanto	a	utilização	de	objetos	literais	é	bastante	útil,	também	é	interessante	expressar	o
modelo	de	dados	utilizando	classes.	Para	isso,	crie	o	arquivo
	./src/app/disciplina.model.ts		com	o	conteúdo	a	seguir:
Apresentando	a	lista	de	disciplinas
43
export	class	Disciplina	{
		nome:	string;
		descricao:	string;
		constructor(nome:	string,	descricao?:	string)	{
				this.nome	=	nome;
				this.descricao	=	descricao;
		}
}
Para	utilizar	mais	recursos	do	TypeScript,	a	classe		Disciplina		possui	dois	atributos:		nome	
e		descricao	,	ambos	do	tipo		string	.	O	método		constructor()		recebe	dois	parâmetros,
ambos	do	tipo		string	:		nome		e		descricao		(que	é	opcional	--	note	o	uso	de		?	).	Para
concluir,	a	classe	é	disponibilizada	para	uso	externo	por	meio	da	instrução		export	.
Para	usar	a	classe		Disciplina	,	modifique	o	Controller	do		AppComponent	:
import	{Component}	from	'@angular/core';
import	{Disciplina}	from	'./disciplina.model';
...
export	class	AppComponent	{
		disciplinas	=	[
				new	Disciplina('Língua	Portuguesa',	'O	objetivo	norteador	...'),
				new	Disciplina('Educação	Física',	'A	Educação	Física	é	...'),
				...
		];
}
Perceba	que	os	elementos	do	atributo		disciplinas		agora	são	instâncias	da	classe
	Disciplina	.	O	mais	interessante	é	que	o	Template	não	precisa	ser	alterado,	já	que	está
utilizando	objetos	com	a	mesma	estrutura	de	antes,	ou	seja,	espera	que	os	itens	do	atributo
	disciplinas		sejam	objetos	que	tenham	os	atributos		nome		e		descricao	.
Adicionando	interação	com	o	usuário
A	apresentação	de	todos	os	dados	das	disciplinas	na	tela	pode	ser	melhorada	usando
interação	com	o	usuário.	Suponha	que	o	usuário	veja	a	lista	das	disciplinas	contendo
apenas	seus	nomes;	ele	deve	clicar	no	nome	de	uma	disciplina	para	ver	sua	descrição.
Além	disso,	para	dar	uma	resposta	visual	para	o	usuário	quando	ele	clicar	no	nome	da
disciplina,	considere	que	será	usada	uma	formatação	em	negrito.
Para	implementar	esses	requisitos	vamos	usar	outros	recursos	do	Angular.
Começando	pelo	Controller	do		AppComponent		são	acrescentados:
Apresentando	a	lista	de	disciplinas
44
o	atributo		selecionado	
o	método		selecionar()	
export	class	AppComponent	{
		selecionado	=	null;
		disciplinas	=	[
				new	Disciplina('Língua	Portuguesa',	'O	objetivo	norteador	da	BNCC	...'),
		...
		];
		selecionar(disciplina)	{
				this.selecionado	=	disciplina;
		}
}
O	atributo		selecionado		será	utilizado	para	que	o	Controller	saiba	qual	disciplina	o	usuário
selecionou.	O	usuário	fará	isso	por	meio	de	uma	chamada	para	o	método		selecionar()	,
que	recebe	o	parâmetro		disciplina		e	o	atribui	para	o	atributo		selecionado	.	Quando	isso
acontecer	(o	usuário	selecionar	uma	disciplina)	o	software	apresentará	a	sua	descrição.
Para	utilizar	mais	recursos	do	desenvolvimento	front-end,	dessa	vez	também	alteramos	o
arquivo		./src/app/app.component.css	:
.selecionado	{
				font-weight:	bold;
}
li	p:nth-child(1)	{
				cursor:	pointer;
				font-size:	12pt;
}
li	p:nth-child(1):hover	{
				font-weight:	bold;
}
li	p:nth-child(2)	{
				font-size:	10pt;
}
O	arquivo	CSS	do		AppComponent		possui	regras	de	formatação:
seletor		.selecionado	:	para	deixar	o	nome	da	disciplina	selecionada	em	negrito
seletor		li	p:nth-child(1)	:	para	que	o	cursor	do	mouse	sobre	o	nome	da	disciplina
seja		pointer		(semelhante	ao	comportamento	do	cursor	em	links)	e	tenha	fonte	de
tamanho	12pt
seletor		li	p:nth-child(1):hover	:	para	que	o	nome	da	disciplina	sob	o	mouse	fique	em
Apresentando	a	lista	de	disciplinas
45
negrito
seletor		li	p:nth-child(2)	:	para	que	a	fonte	da	descrição	seja	de	tamanho	10pt
Agora,	o	Template:
<h1>Disciplinas</h1>
<hr>
<ul>
		<li	*ngFor="let	disciplina	of	disciplinas"	(click)="selecionar(disciplina)">
						<p	[class.selecionado]="selecionado	==	disciplina">{{disciplina.nome}}</p>
						<p	*ngIf="selecionado	==	disciplina">{{disciplina.descricao}}</p>
		</li>
</ul>
A	primeira	coisa	a	destacar	é	o	recurso	que	proporciona	a	interação	com	o	usuário.	Como	já
comentado,	o	requisito	determina	que	o	usuário	possa	clicar	no	nome	da	disciplina.	Isso	é
um	ação	do	usuário	para	a	interface.	O	Angular	implementa	isso	por	meio	de	eventos	e	de
uma	sintaxe	própria:	o	atributo		(click)		no	elemento		li		indica	que	estamos	fornecendo
um	tratador	para	o	evento		click	;	o	tratador	é	o	valor	do	atributo,	ou	seja,	uma	expressão
que	representa	a	chamada	do	método		selecionar(disciplina)	,	definido	no	Controller.
Outra	característica	importante	é	a	chamada	do	método		selecionar()		fornece	como
parâmetro		disciplina	,	que	é	o	item	da	repetição	realizada	pelo		*ngFor	.	Se	você	voltar	no
código	do	Controller	vai	ver	que	esse	parâmetro	é	atribuído	para	o	atributo		selecionado	,
que	faz	justamente	isso:	guarda	uma	referência	para	a	disciplina	selecionada.
O	próximo	passo	é	garantir	o	determinado	no	requisito	no	sentido	da	apresentação.	Para
fazer	com	que	a	disciplina	selecionada	fique	em	negrito	vamos	aplicar	uma	classe	CSS
chamada		selecionado		em	um	elemento		p		que	contém	o	nome	da	disciplina	sempre	que	a
	disciplina		da	repetição	do		*ngFor		for	igual	à	disciplina	selecionada.	O	Angular	fornece
um	recurso	para	modificar	características	de	elementos	do	HTML	por	meio	de	expressões.
Esse	recurso	está	sendo	usado	na	tag		<p>	:		[class.selecionado]		parece	como	um	atributo
do	HTML,	mas	é	tratado	pelo	Angular	antes	de	o	HTML	ser	fornecido	para	o	browser,
modificando	o	atributo		class		e	inserindo	nele	a	classe	CSS	chamada		selecionado	.	Nesse
sentido,	o	valor	do	atributo	é	uma	expressão	e,	nesse	caso,	uma	expressão	booleana:
	selecionado	==	disciplina		determina,	então,	que	o	elemento		p		terá	o	atributo		class	
com	valor		selecionado		se	a		disciplina		atual	da	iteração	do		*ngFor		for	igual	à	disciplina
selecionada.
Para	finalizar,	o	software	deve	apresentar	a	descrição	da	disciplina	selecionada.	Para	isso
vamos	usar	outra	diretiva,	a		NgIf	.	Veja	o	trecho:
Apresentando	a	lista	de	disciplinas
46
<li	*ngFor="let	disciplina	of	disciplinas"	...>
				...
				<p	*ngIf="selecionado	==	disciplina">{{disciplina.descricao}}</p>
</li>
A	diretiva		*ngIf		é	aplicada	no	elemento		p		usado	para	apresentar	a	descrição	da
disciplina.	Como	o	propósito	dessa	diretiva	é	funcionar	como	um	condicional	o	valor	que	o
atributo	recebe	é	uma	expressão	booleanda:		selecionado	==	disciplina	.	Se	a	expressão
for	verdadeira	(se	a		disciplina		da	repetição	do		*ngFor		for	igual	à	disciplina	selecionada),
o	elemento		p		estará	presente	no	HTML,	caso	contrário,	não	estará	presente.	Perceba	que
usei	o	termo	"estar	presente"	ao	invés	de	"visível"	porque	é	isso	que	acontece.	Se	a
expressão	booleanda	for	falsa,	o	elemento	no	qual	a	diretiva		*ngIf		é	aplicada	nem	está
presente	no	HTML.
Para	ilustrar	isso,	veja	um	trecho	da	estrutura	HTML	no	browser:
<ul	_ngcontent-c0="">
		<!--bindings={"ng-reflect-ng-for-of":	"[object	Object],[object	Object"}-->
		<li	_ngcontent-c0="">
						<p	_ngcontent-c0=""	class="selecionado">Língua	Portuguesa</p>
						<!--bindings={"ng-reflect-ng-if":	"true"}-->
						<p	_ngcontent-c0="">O	objetivonorteador	da	BNCC	de	Língua	Portuguesa	...</p>
		</li>
		<li	_ngcontent-c0="">
						<p	_ngcontent-c0=""	class="">Educação	Física</p>
						<!--bindings={"ng-reflect-ng-if":	"false"}-->
		</li>
		...
</ul>
Os	vários	comentários	presentes	no	HTML	parecem	ser	algo	que	o	Angular	utiliza	para
tratar	o	comportamento	da	interface?	É	justamente	isso	que	acontece	(não	precisa	tentar
interpretar	os	comentários	agora).	No	caso	desse	exemplo,	o	usuário	clicou	na	disciplina
"Língua	Portuguesa".	Características	importantes:
para	o	elemento		li		correspondente	à	disciplina	selecionada:
o	elemento		p		que	mostra	o	nome	da	disciplina	possui		class="selecionado"	
o	elemento		p		que	mostra	a	descrição	da	disciplina	está	presente	no	HTML
para	os	demais	elementos		li	:
o	elemento		p		que	mostra	o	nome	da	disciplina	não	possui	o	atributo		class	
o	elemento		p		que	mostra	a	descrição	da	disciplina	não	existe	no	HTML
Apresentando	a	lista	de	disciplinas
47
Se	você	já	tiver	programado	para	front-end	anteriormente	vai	entender	melhor	a
complexidade	do	que	está	acontecendo	aqui,	que	o	Angular	não	passa	para	o	programador.
O	Angular	está	realizando	a	chamada	manipulação	do	DOM	para	que	o	HTML	entregue
para	o	browser	tenha	o	comportamento	esperado	(ou	explícito	no	software).
Por	fim,	a	figura	a	seguir	ilustra	o	funcionando	do	software	no	browser.
Figura	2.7.2	-	Execução	do	software	no	browser,	listando	disciplinas	e	interagindo	com	o
usuário
Pronto,	esse	capítulo	mostrou	a	utilização	de	vários	recursos	do	Angular	para	implementar
o	requisito	"Apresentar	a	lista	das	disciplinas".
Apresentando	a	lista	de	disciplinas
48
[info]	Para	resumir:
utilizar	recursos	da	Programação	Orientada	a	Objetos	é	muito	bom	para
representação	do	modelo	de	dados
a	diretiva		NgForOf		é	utilizada	para	repetir	elementos	no	Template	com	base	em
uma	coleção	de	itens	(um	array)
a	diretiva		NgIf		é	utilizada	para	incluir	ou	excluir	elementos	do	Template	com	base
em	um	condicional
	(click)		representa	a	sintaxe	do	Angular	para	criar	tratadores	de	eventos
	[class.selecionado]		representa	a	sintaxe	do	Angular	para	adicionar	ou	remover
atributos	no	HTML
Apresentando	a	lista	de	disciplinas
49
Cadastrando	uma	disciplina
[info]	Objetivos	do	capítulo:
demonstrar	o	uso	de	formulários	e	two-way	data	binding
implementar	o	requisito	"Cadastrar	disciplina"
Branches:	livro-cadastrando-disciplina
Neste	capítulo	vamos	começar	pelo	final:	primeiro,	veja	a	figura	que	ilustra	como	o	software
estará	ao	final	do	capítulo.
Figura	2.8.1	-	Tela	do	software	apresentando	a	lista	das	disciplinas	e	o	formulário	de
cadastro
A	tela	do	aplicativo	tem	duas	funções:	na	primeira	parte,	apresenta	a	lista	das	disciplinas;	na
segunda	parte,	apresenta	um	formulário	que	permite	o	cadastro	de	uma	disciplina.	A
primeira	parte	você	já	conhece	do	capítulo	anterior.	Agora,	veremos	os	detalhes	para	o
formulário	de	cadastro.
Cadastrando	uma	disciplina
50
https://github.com/jacksongomesbr/angular-escola/tree/livro-cadastrando-disciplina
Antes	de	prosseguir,	um	fator	importante:	o	projeto	original	criado	pelo	Angular	CLI	não
suporta	formulários.	Isso	mesmo	que	você	leu.	O	Angular	trata	formulários	de	três	formas
diferentes,	uma	delas,	a	que	vamos	utilizar,	chamada	de	template	driven	forms	(algo	como
formuários	orientados	a	templates).
Para	habilitar	o	suporte	a	formulários	é	necessário	importar	o	módulo		FormsModule		no	root
module:
import	{BrowserModule}	from	'@angular/platform-browser';
import	{NgModule}	from	'@angular/core';
import	{FormsModule}	from	'@angular/forms';
import	{AppComponent}	from	'./app.component';
@NgModule({
		...
		imports:	[
				BrowserModule,
				FormsModule
		],
		...
})
export	class	AppModule	{
}
O	módulo		FormsModule		está	definido	no	pacote		@angular/forms		e	é	importado	no
	AppModule		por	meio	do	atributo		imports		dos	metadados	da	classe.	A	partir	de	então	a
utilização	de	formulários	do	tipo	template-driven	forms	está	garantida.
O	formulário	de	cadastro	tem	dois	campos:	nome	e	descrição.	O	comportamento	esperado
pelo	usuário	é	preencher	os	valores	dos	campos,	clicar	no	botão	"Salvar"	e	ver	a	lista	de
disciplinas	atualizada,	contendo	a	disciplina	que	acabou	de	ser	cadastrada.
Para	fazer	isso,	primeiro	vamos	ao	Controller	do		AppComponent	:
Cadastrando	uma	disciplina
51
...
export	class	AppComponent	{
		selecionado	=	null;
		nome	=	null;
		descricao	=	null;
		disciplinas	=	[
				new	Disciplina('Língua	Portuguesa',	'O	objetivo	norteador	da	BNCC	de	...'),
						...
		];
		salvar()	{
				const	d	=	new	Disciplina(this.nome,	this.descricao);
				this.disciplinas.push(d);
				this.nome	=	null;
				this.descricao	=	null;
		}
}
São	adicionados	dois	atributos	e	um	método:
	nome	:	está	ligado	ao	campo	nome	do	formulário	por	meio	de	data	binding
	descricao	:	está	ligado	ao	campo	descricao	do	formulário	por	meio	de	data	binding
	salvar()	:	é	executado	quando	o	usuário	clicar	no	botão	"Salvar"
Os	dois	atributos	são	inciados	com		null	.	O	método		salvar()		cria	uma	instância	da
classe		Disciplina		usando	os	atributos		nome		e		descrição	,	respectivamente.
Posteriormente,	adiciona	esse	objeto	ao	vetor		disciplinas		por	meio	do	método		push()	.
Por	fim,	atribui	o	valor		null		novamente	aos	atributos		nome		e		descricao	.
Mas...	o	que	significa	um	atributo	do	Controller	estar	ligado	a	um	campo	do	formulário	via
data	binding?	Você	já	sabe	que	data	binding	é	o	recurso	do	Angular	que	faz	com	que	o
valor	de	um	atributo	do	Controller	seja	apresentado	no	Template	por	meio	de	interpolação.
E	quanto	ao	formulário?	Vamos	ao	Template:
Cadastrando	uma	disciplina
52
<h1>Disciplinas</h1>
...
<h2>Cadastrar</h2>
<p>Use	este	formulário	para	cadastrar	uma	disciplina.</p>
<form	#cadastro="ngForm"	(submit)="salvar()">
				<div>
								<label	for="nome">Nome</label><br>
								<input	type="text"	id="nome"	name="nome"	[(ngModel)]="nome"	required>
				</div>
				<div>
								<label	for="descricao">Descrição</label><br>
								<textarea	id="descricao"	name="descricao"	[(ngModel)]="descricao"
																		cols="70"	rows="5">
								</textarea>
				</div>
				<button	type="submit"	class="btn	btn-primary"	[disabled]="!cadastro.valid">
								Salvar
				</button>
</form>
Como	a	parte	da	lista	das	disciplinas	não	muda	muito,	vamos	omitir	essa	parte	e	apresentar
o	formulário,	começando	pela	tag		<form>	.	Em	termos	de	HTML,	a	tag	possui	um	atributo
	#cadastro	,	com	valor		ngForm	.	Esse	recurso,	na	verdade,	é	uma	sintaxe	do	Angular	para
criar	uma	variável	(chamada		cadastro	)	vinculada	ao	formulário.	Importante	também
destacar	o	evento		submit	.	Você	já	entende	a	sintaxe		(submit)	,	então	o	tratador	do	evento
é	uma	chamada	ao	método		salvar()	.
Na	sequência	são	definidos	os	campos	do	formulário.	A	parte	mais	importante	está	nas
	tags		input	e		textarea	,	principalmente	o	que,	em	termos	de	HTML,	parece	um	atributo:
	[(ngModel)]	.	Você	já	sabe	a	sintaxe	para	eventos	(entre	parênteses)	e	já	viu	que	o	Angular
consegue	alterar	um	atributo	do	HTML	por	meio	de	colchetes.	Essa	sintaxe,	que	mistura	as
duas	anteriores,	é	a	sintaxe	do	recurso	two-way	data	binding.	No	campo	para	o	nome,
	[(ngModel)]		tem	o	valor		nome	,	para	o	campo	descrição,	tem	o	valor		descricao	.	Ambos
são	atributos	do	Controller.	Assim,	o	two-way	data	binding	significa	que	o	valor	do	atributo
pode	ser	modificado	por	meio	de	uma	alteração	do	campo	de	formulário	correspondente,	e
vice-versa:
se	o	valor	do	atributo		nome		for	modificado	no	Controller,	o	Template	será	atualizado,
mostrando	esse	valor	no		input	
se	o	valor	do	atributo		nome		for	modificado	no	Template,	por	uma	alteração	no		input	,
esse	valor	estará	disponível	no	Controller
Por	isso	o	two-way:	duas	vias.	A	figura	a	seguir	ilustra	esse	processo.
Cadastrando	uma	disciplina
53
Figura	2.8.2	-	Ilustração	do	two-way	data	binding,	ligando	formulário	e	Controller
O	formulário	tem	mais	uma	característica:	a	entrada	do	usuário	está	passando	por
validação.	O	elemento		input		para	o	camponome	tem	o	atributo		required	,	que	o	torna	de
preenchimento	obrigatório.	A	partir	de	então	há	um	comportamento	muito	interessante	para
o	botão	"Salvar":	o	elemento	button	possui	um	atributo		disabled	,	que	é	modificado
conforme	a	expressão		!cadastro.valid	.	Lembra	da	variável	de	template		#cadastro	?	Aqui
ela	é	usada	como	uma	referência	ao	formulário.	Portanto,	se	o	formulário	de	cadastro
estiver	válido,	o	botão	"Salvar"	estará	habilitado	para	clique.	Caso	contrário,	estará
desabilitado.
Execute	o	software	no	browser	para	notar	o	comportamento	citado	no	capítulo.
[info]	Resumo	do	capítulo:
Implementamos	o	requisito	"Cadastrar	uma	disciplina"
Utilizamos	o	recurso	two-way	data	binding
Utilizamos	formulário	para	receber	entrada	do	usuário
Cadastrando	uma	disciplina
54
Excluindo	uma	disciplina
[info]	Objetivos	do	capítulo:
demonstrar	a	implementação	do	requisito	"Excluir	uma	disciplina"
Branch:	livro-excluindo-disciplina
Este	é	um	capítulo	mais	simples.	Basicamente	os	recursos	utilizados	já	foram
apresentados,	então	ele	é	mais	curto.
Primeiro,	um	trecho	do	Controller	do		AppComponent	:
...
export	class	AppComponent	{
		selecionado	=	null;
		nome	=	null;
		descricao	=	null;
		disciplinas	=	[
				new	Disciplina('Língua	Portuguesa',	'...'),
				...
		];
		salvar()	{
		...
		}
		excluir(disciplina)	{
				if	(confirm('Tem	certeza	que	deseja	excluir	a	disciplina	"'
								+	disciplina.nome	+	'"?'))	{
						const	i	=	this.disciplinas.indexOf(disciplina);
						this.disciplinas.splice(i,	1);
				}
		}
}
Com	exceção	do	código	omitido,	que	você	já	conheceu	nos	capítulos	anteriores,	o	método
	excluir()		recebe	como	parâmetro	um	objeto,	chamado		disciplina	.	Esse	método	exclui
uma	disciplina	da	lista,	mas,	antes,	solicita	uma	confirmação	do	usuário	(por	isso	está
usando	a	função		confirm()	).	Se	o	usuário	confirmar	que	deseja	excluir	a	disciplina,	então
o	código	prossegue:
encontra	o	índice	da	disciplina	na	lista	usando	o	método		indexOf()	
remove	um	elemento	da	lista	usando	o	método		splice()	
Agora,	então,	um	trecho	do	código	do	Template:
Excluindo	uma	disciplina
55
https://github.com/jacksongomesbr/angular-escola/tree/livro-excluindo-disciplina
<h1>Disciplinas</h1>
<hr>
<ul>
				<li	*ngFor="let	disciplina	of	disciplinas">
								{{disciplina.nome}}
								<button	(click)="excluir(disciplina)">
												Excluir
								</button>
				</li>
</ul>
<h2>Cadastrar</h2>
<p>Use	este	formulário	para	cadastrar	uma	disciplina.</p>
<form	#cadastro="ngForm"	(submit)="salvar()">
...
</form>
A	parte	importante	do	template	é	o	elemento		button		ao	lado	do	nome	da	disciplina.	Há	um
tratador	do	evento		(click)		que	chama	o	método		excluir()		passando	como	parâmetro	a
	disciplina		atual	da	repetição	do		*ngFor	.
O	resultado	da	execução	do	software	no	browser	é	ilustrado	pela	figura	a	seguir.
Excluindo	uma	disciplina
56
Figura	2.9.1	-	Execução	do	software	no	browser	ilustrando	a	confirmação	do	usuário	para
excluir	uma	disciplina
Esse	capitulo	é	bem	curto	e	não	há	muito	o	que	resumir,	mas	é	bom	notar	que	os	conceitos
vistos	nos	capítulos	anteriores	continuam	funcionando	aqui,	mesmo	que	em	aplicações
diferentes.
Excluindo	uma	disciplina
57
Editando	dados	de	uma	disciplina
[info]	Objetivos	do	capítulo:
demonstrar	a	implementação	do	requisito	"Editar	dados	de	uma	disciplina"
reforçar	os	conceitos	anteriores
demonstrar	a	implementação	mais	completa	de	um	CRUD
Branch:	livro-crud-disciplina
Como	o	capítulo	anterior,	esse	capítulo	não	é	muito	extenso	em	termos	de	conceitos	novos.
Entretanto,	ele	reúne	os	capítulos	anteriores	para	implementar	um	CRUD,	que	significa:
Create	(cadastrar)
Retrieve	(recuperar,	listar,	consultar)
Update	(atualizar,	editar)
Delete	(excluir)
A	figura	a	seguir	ilustra	a	interface	do	software	como	construída	ao	final	do	capítulo.
Editando	dados	de	uma	disciplina
58
https://github.com/jacksongomesbr/angular-escola/tree/livro-crud-disciplina
Figura	2.10.1	-	Software	com	o	CRUD	de	Disciplinas
A	interface	continua	com	duas	partes:	uma	apresentando	uma	lista	e	outra	apresentando
um	formulário.	Na	lista,	para	cada	item,	há	dois	botões:	"Excluir"	e	"Editar".	Ao	clicar	no
botão	"Excluir"	o	software	solicita	uma	confirmação	do	usuário.	Ao	clicar	no	botão	"Editar"
os	dados	da	disciplina	em	questão	são	apresentados	no	formulário	(nome	e	descrição).
Nesse	momento	o	formulário	entra	no	modo	de	edição	e:
se	o	usuário	clicar	em	"Salvar"	os	dados	da	disciplina	serão	atualizados
se	o	usuário	clicar	em	"Cancelar"	qualquer	alteração	não	será	armazenada
O	modo	padrão	do	formulário	é	o	cadastro.	Nesse	sentido	se	o	usuário	preencher	os
campos	(nome	e	descrição)	e:
clicar	em	"Salvar",	os	dados	serão	armazenados	em	uma	nova	disciplina,
apresentando-a	na	lista
clicar	em	"Cancelar",	os	dados	não	serão	armazenados
Vamos	ao	código-fonte.	Primeiro,	um	trecho	do	Controller:
Editando	dados	de	uma	disciplina
59
...
export	class	AppComponent	{
		editando	=	null;
		nome	=	null;
		descricao	=	null;
		disciplinas	=	[
				new	Disciplina('Língua	Portuguesa',	'O	objetivo	norteador	da	BNCC...'),
				...
		];
		salvar()	{
				if	(this.editando)	{
						this.editando.nome	=	this.nome;
						this.editando.descricao	=	this.descricao;
				}	else	{
						const	d	=	new	Disciplina(this.nome,	this.descricao);
						this.disciplinas.push(d);
				}
				this.nome	=	null;
				this.descricao	=	null;
				this.editando	=	null;
		}
		excluir(disciplina)	{
				if	(this.editando	==	disciplina)	{
						alert('Você	não	pode	excluir	uma	disciplina	que	está	editando');
				}	else	{
						if	(confirm('Tem	certeza	que	deseja	excluir	a	disciplina	"'
										+	disciplina.nome	+	'"?'))	{
								const	i	=	this.disciplinas.indexOf(disciplina);
								this.disciplinas.splice(i,	1);
						}
				}
		}
		editar(disciplina)	{
				this.nome	=	disciplina.nome;
				this.descricao	=	disciplina.descricao;
				this.editando	=	disciplina;
		}
		cancelar()	{
				this.nome	=	null;
				this.descricao	=	null;
				this.editando	=	null;
		}
}
As	novidades	são:
adição	do	atributo		editando	:	é	inicializado	com	null	e	manterá	uma	referência	para	a
Editando	dados	de	uma	disciplina
60
disciplina	que	está	sendo	editada	(quando	houver	alguma)
atualização	no	método	salvar()	:	para	tratar	a	situação	do	formulário	(cadastrando	ou
editando	disciplina)
atualização	no	método		excluir()	:	para	tratar	a	situação	em	que	o	usuário	quer	excluir
uma	disciplina	que	está	sendo	editada
adição	do	método		editar()	
O	método		salvar()		tem	um	novo	comportamento:	se	o	usuário	estiver	editando	uma
disciplina	(verifica	o	valor	do	atributo		editando	),	então	usa	os	dados	do	formulário	e
atualiza	os	dados	da	disciplina	que	está	sendo	editada.	Caso	contrário,	continua	com	o
comportamento	anterior:	usa	os	dados	do	formulário	para	criar	uma	instância	de
	Disciplina		e	adiciona	no	vetor		disciplinas	.
O	método		excluir()		tem	um	novo	comportamento:	se	o	usuário	estiver	editando	uma
disciplina	(verifica	o	valor	do	atributo	editando),	então	informa	o	usuário	que	não	é	possível
excluir	a	disciplina	que	está	sendo	editada.	Caso	contrário,	continua	com	o	comportamento
normal:	solicita	uma	confirmação	do	usuário	e	exclui	a	disciplina.
O	método		editar()		recebe	como	parâmetro	um	objeto	que	representa	a	disciplina	a	ser
editada,	atualiza	os	campos	do	formulário	com	os	atributos	de		disciplina		e	faz	com	que	o
atributo		editando		receba		disciplina		para	indicar	que	o	formulário	está	no	modo	de
edição	(há	uma	disciplina	sendo	editada).
O	método		cancelar()		tem	a	função	de	reiniciar	o	formulário	para	os	valores-padrão,
atributo	o	valor		null		para	os	atributos		nome	,		descricao		e		editando	.
Para	concluir,	o	Template:
Editando	dados	de	uma	disciplina
61
<h1>Disciplinas</h1>
<hr>
<ul>
				<li	*ngFor="let	disciplina	of	disciplinas">
								{{disciplina.nome}}
								<button	(click)="excluir(disciplina)">
												Excluir
								</button>
								<button	(click)="editar(disciplina)">Editar
								</button>
				</li>
</ul>
<h2>Cadastrar</h2>
<p>Use	este	formulário	para	cadastrar	ou	editar	uma	disciplina.</p>
<form	#cadastro="ngForm"	(submit)="salvar()">
				<div>
								<label	for="nome">Nome</label><br>
								<input	type="text"	id="nome"	name="nome"	[(ngModel)]="nome"	required>
				</div>
				<div>
								<label	for="descricao">Descrição</label><br>
								<textarea	id="descricao"	name="descricao"	[(ngModel)]="descricao"
																		cols="70"	rows="5"></textarea>
				</div>
				<button	type="submit"	[disabled]="!cadastro.valid">Salvar</button>
				<button	type="reset"	(click)="cancelar()">Cancelar</button>
</form>
Para	ilustrar	a	interface	completa,	a	figura	a	seguir	ilustra	o	processo	da	interface	CRUD
para	Disciplina.
Editando	dados	de	uma	disciplina
62
Figura	2.10.2	-	Relações	entre	os	elementos	do	Template	e	do	Controller
A	figura	demonstra	as	várias	relações	entre	os	elementos	do	Template	e	do	Controller.
Como	ela	resume	os	conceitos	vistos	neste	e	nos	quatro	capítulos	anteriores,	se	você
chegou	aqui	e	está	um	pouco	perdido,	não	se	preocupe,	pode	acontecer.	Reserve	um
pouco	mais	de	tempo	para	estudar	a	figura	e	o	código-fonte	e,	se	necessário,	volte	nos
capítulos	anteriores.
O	conjunto	de	funcionalidades	implementadas	até	aqui	demonstram	vários	recursos	do
Angular,	mas	a	interface	gráfica	não	é	das	melhores.	No	próximo	capítulo	vamos	aprender
como	melhorar	o	aspecto	visual	do	software.
Editando	dados	de	uma	disciplina
63
Interação	entre	componentes
Objetivos	do	capítulo:
demonstrar	a	modularização	do	código	utilizando	componentes
demonstrar	a	integração	entre	componentes	usando	input	e	output
Branches:	livro-componentes-lista	e	livro-componentes-editor.
Uma	vez	que	a	quantidade	de	funcionalidades	em	um	componente	começa	a	aumentar,
prejudicando,	por	exemplo,	a	legibilidade	e	a	organização	do	código-fonte,	o	componente
torna-se	um	candidato	a	passar	por	um	processo	de	modularização.
O		AppComponent	,	no	momento,	fornece	as	funcionalidades	de	CRUD	de	disciplinas,	ou	seja:
Listar	disciplinas
Cadastrar	disciplinas
Editar	disciplinas
Excluir	disciplinas
Como	alternativa	ao	fato	de	haver	um	só	componente	realizando	todas	as	essas
funcionalidades	vamos	utilizar	o	conceito	de	componentes	do	Angular	e	criar	níveis	de
interações	entre	eles.
Criando	componentes
O	Angular	CLI	é	a	ferramenta	ideal	para	criar	conteúdo	para	o	software,	já	vimos	isso
quando	iniciamos	o	próprio	projeto	a	partir	de	uma	linha	de	código.	Outro	comando
importante	é	o	generate	(cujo	atalho	é	g).	Ele	é	usado	para	criar	conteúdo	como
componentes,	módulos	e	serviços.	Para	cada	tipo	de	comando	há	uma	opção,	como	c,
atalho	para	component.
Vamos	começar	pelo	componente		ListaDeDisciplinas	,	que	implementa	a	funcionalidade
de	listar	disciplinas.	Para	criá-lo	use	a	linha	de	comando:
ng	g	c	ListaDeDisciplinas	--spec	false
O	comando	cria	o	diretório		./src/app/lista-de-disciplinas		e,	dentro	dele,	os	arquivos
necessários	para	o	componente,	ou	seja	CSS,	Template	e	Controller.
Interação	entre	componentes
64
https://github.com/jacksongomesbr/angular-escola/tree/livro-componentes-lista
https://github.com/jacksongomesbr/angular-escola/tree/livro-componentes-editor
Componente	lista	de	disciplinas
O	componente	ListaDeDisciplinas	é	um	tipo	de	componente	diferente	do	que	vimos	até
agora:	ele	não	funciona	sozinho.	Isso	quer	dizer	que	ele	precisa	ser	inserido	em	outro
componente	para	funcionar.	No	nosso	contexto,	o	componente	App	inclui	e	utiliza	o
componente	ListaDeDisciplinas.	Vamos	chamar	o	componente	App	de	host	(hospedeiro)
e	o	componente	ListaDeDisciplinas	de	guest	(hóspede).	Nessa	comunicação	o	host	deve
fornecer	recursos	necessários	para	o	guest	funcionar,	o	que	chamamos	input	(entrada).
Por	outro	lado,	quando	o	guest	notifica	o	host	sempre	que	fizer	qualquer	coisa	importante,
o	que	chamamos	output	(saída	ou	evento).
Pode	ser	que	não	tenha	te	ocorrido,	mas	é	uma	analogia	bem	interessante.	Imagine	que
você	está	hospedando	um	convidado	na	sua	casa.	Você	é	o	host,	enquanto	seu	convidado
é	o	guest.	Sua	casa	é	onde	você	irá	receber	seu	convidado.	O	convidado	precisa	de	um
lugar	para	dormir,	então	você	fornece	para	ele	uma	cama	(input).	Seu	convidado	te	notifica
quer	ir	embora	(output),	então	você	se	despede	dele	e	o	encaminha	até	a	saída.	Pensou
naquele	convidado	exigente	(chato)?	Com	um	componente	guest	é	a	mesma	coisa:	muita
necessidade	e	muita	notificação!
A	figura	a	seguir	ilustra	o	componente	ListaDeDisciplinas.
Figura	3.1.1	-	Ilustração	do	componente	ListaDeDisciplinas	no	browser
O	componente	apresenta	uma	lista	de	disciplinas.	Cada	item	da	lista	contém:
o	nome	da	disciplina
um	botão	para	excluir	a	disciplina
Interação	entre	componentes
65
um	botão	para	editar	a	disciplina
Os	dois	botões	não	executam	as	ações	correspondentes	(excluir	ou	editar)	porque	isso	não
é	responsabilidade	desse	componente.	O	que	o	componente	faz	é	notificar	o	host	que	o
usuário	deseja	excluir	ou	editar	determinada	disciplina.	Além	disso	o	componente,	ao
apresentar	a	lista	das	disciplinas,	precisa	saber	qual	disciplina	está	sendo	editada,	para	que
destaque	essa	disciplina	na	lista	(perceba,	na	figura,	o	ícone	do	lápis	e	o	fundo	da	linha	com
a	cor	cinza	na	disciplina	"Língua	Portuguesa").	Assim:
input:	a	lista	das	disciplinas	e	a	disciplina	que	está	sendo	editada;	e
output:	a	disciplina	que	o	usuário	deseja	excluir	ou	editar.
O	host	utiliza	(ou	recebe)	guest,	então	ele	deve	fornecer	os	inputs	requeridos.	Além	disso,
o	host	também	pode	realizar	alguma	ação	quando	for	notificado	de	que	o	usuário	deseja
realizar	uma	exclusão	ou	uma	edição	de	uma	disciplina.
A	figura	a	seguir	ilustra	essa	relação	entre	os	dois	componentes.
Figura	3.1.2	-	Diagrama	demonstrando	a	interação	entre	os	componentes	App	e
ListaDeDisciplinas
O	diagrama	apresentado	pela	figura	demonstra	as	conexões	entre	os	componentes:
App	fornece	as	entradas	para	ListaDeDisciplinas
os	atributos		disciplinas		e		editando		de		AppComponent		são	vinculados	aos	input
	disciplinas		e		editando		do		ListaDeDisciplinasComponent	
ListaDeDisciplinas	notifica	App	quando	o	usuário	desejar	excluir	ou	editar	uma
disciplina
o	método		editar()		do		AppComponent		é	executado	quando	ocorrer	o	output
	onEditar	
o	método		excluir()		do		AppComponent		é	executado	quando	ocorrer	o	output
Interação	entre	componentes
66
	onExcluir	
[info]	O	diagrama	dos	componentes
A	UML	possui	um	diagrama	para	representar	componentes	de	um	software	e	as
relações	entre	eles.	Entretanto,	por	ser	uma	representação	gráfica	mais	formal,	requer
que	entradas	e	saídas	sejam	interfaces.	Aqui	adotamos	uma	simplificação	desse
diagrama	para	suportar	o	conceito	de	Input	e	Output	do	Angular.
Uma	observação	importante:	os	nomes	dos	atributos	das	classes	(host	e	guest)	não
precisam	ser	os	mesmos.
Antes	de	utilizar	o	componente	ListaDeDisciplinas	no	App,	vamos	ver	detalhes	da	sua
composição.	Primeiro,	o	Controller:
import	{Component,	EventEmitter,	Input,	OnInit,	Output}	from	'@angular/core';
@Component({
		selector:	'app-lista-de-disciplinas',
		...
})
export	class	ListaDeDisciplinasComponent	implements	OnInit	{
		@Input()
		disciplinas	=	null;
		@Input()
		editando	=	null;
		@Output()
		onEditar	=	new	EventEmitter<any>();
		@Output()
		onExcluir	=	new	EventEmitter<any>();
		constructor()	{
		}
		ngOnInit()	{
		}
		excluir(disciplina)	{
				this.onExcluir.emit(disciplina);
		}
		editar(disciplina)	{
				this.onEditar.emit(disciplina);
		}
}
Interação	entre	componentes
67
Atenção	para	os	atributos		disciplinas		e		editando	.	Ambos	são	anotados	com		@Input()	,
o	que	indica	para	o	Angular	tratá-los	como	input.	Os	atributos		onEditar		e		onExcluir		são
anotados	com		@Output()	,	o	que	indica	para	o	Angular	tratá-los	como	output.	Além	disso,
perceba	também	mudanças	na	linha	do		import	.
Na	prática,	os	atributos		onEditar		e		onExcluir		definem	eventos,	por	isso	são	inicializados
com	uma	instância	de		EventEmitter	,	a	classe	do	Angular	pararepresentar	eventos.	Note,
na	instanciação	de		EventEmitter	,	que	o	código	define	o	tipo	de	dados	do	evento	utilizando
a	notação	de	diamante:		<any>	.	Isso	é	melhor	interpretado	assim:	um	evento	pode	carregar
consigo	alguma	informação	(dados)	e,	para	isso,	é	importante	indicar	o	tipo	desses	dados.
Os	métodos		excluir(disciplina)		e		editar(disciplina)		são	utilizados,	respectivamente,
como	tratadores	de	eventos	para	quando	o	usuário	clicar	nos	botões	correspondentes,
escolhendo	excluir	ou	editar	uma	disciplina.	O	importante	aqui	é	que,	como	estamos
utilizando	eventos	(output),	não	queremos	que	seja	responsabilidade	desse	componente
ListaDeDisciplinas	realizar	essas	tarefas.	Pelo	contrário,	o	esperado	é	notificar	o	host	de
que	isso	aconteceu.	Para	indicar	para	o	host	que	uma	disciplina	deve	ser	excluída	é	usada
a	chamada	para	o	método		this.onExcluir.emit(disciplina)	.	Isso	fará	um	"disparo"	do
evento,	notificando	o	host	de	que	ele	ocorreu,	e	incluirá,	como	dado	do	evento,	a	disciplina
em	questão	(o	objeto		disciplina	).	Da	mesma	forma,	para	notificar	o	host	que	deve	editar
uma	disciplina	é	usada	uma	chamada	para	o	método		this.onEditar.emit(disciplina)	.
O	Template	do	ListaDeDisciplinas	contém:
Interação	entre	componentes
68
<table	class="table	table-hover	table-bordered">
		<thead	class="thead-light">
		<tr>
				<th>Disciplina</th>
				<th	width="200">Ações</th>
		</tr>
		</thead>
		<tbody>
		<tr	*ngFor="let	disciplina	of	disciplinas"
						[class.table-active]="editando	==	disciplina">
				<td>
						<i	*ngIf="editando	==	disciplina"
									class="fa	fa-pencil-square"></i>
						{{disciplina.nome}}
				</td>
				<td>
						<button	class="btn	btn-sm	btn-danger"
														(click)="excluir(disciplina)">
								<i	class="fa	fa-trash"></i>	Excluir
						</button>
						<button	class="btn	btn-sm	btn-primary"
														(click)="editar(disciplina)">
								<i	class="fa	fa-pencil-square"></i>	Editar
						</button>
				</td>
		</tr>
		</tbody>
</table>
Percebeu	semelhança	com	o	Template	do	capítulo	anterior?	Isso	não	é	coincidência.	Foi
realmente	isso	que	aconteceu.	Tanto	é	que	a	melhor	dica	para	se	trabalhar	com	múltiplos
componentes	em	Angular,	pelo	menos	enquanto	você	for	um	dev	iniciante,	é	usar	apenas
um	componente	e	implementar	nele	todas	as	funcionalidades	desejadas.	Depois,	a	tarefa	é
"recortar"	partes	desse	componente	e	usar	em	outros	componentes.
A	forma	pela	qual	o	host	incorpora	o	guest	e	informa	o	vínculo	com	input	e	output	é	por
meio	do	Template.	Veja	o	trecho	a	seguir,	do	Template	do	componente	App:
<app-lista-de-disciplinas	
				[disciplinas]="disciplinas"	
				[editando]="editando"
				(onEditar)="editar($event)"	
				(onExcluir)="excluir($event)">
</app-lista-de-disciplinas>
Primeiro,	o	elemento		app-lista-de-disciplinas		é	utilizado	para	indicar	para	o	Angular	que
nesse	local	deve	ser	apresentado	o	componente	ListaDeDisciplinas.	Isso	acontece	por
causa	do		selector		do	componente	ListaDeDisciplinas	(veja	o	Controller	desse
Interação	entre	componentes
69
componente).
Segundo,	a	sintaxe	que	tem	um	atributo	HTML	com	nome	entre	colchetes	você	já	conhece.
É	a	mesma	que	já	utilizamos	para	definir,	por	exemplo,	a	classe	CSS	de	um	elemento	do
HTML	com	base	em	uma	condição	(ex:	o	fundo	da	linha	da	tabela	na	cor	cinza	quando	a
disciplina	está	sendo	editada).	Então	o	trecho		[disciplinas]="disciplinas"		indica	o	uso	de
Data	Binding:	o	input	chamado		disciplinas		está	vinculado	ao	atributo		disciplinas	.	Da
mesma	forma	o	trecho		[editando]="editando"		usa	Data	binding	para	vincular	o	input
	editando		ao	atributo		editando	.
Por	fim,	a	sintaxe	que	tem	um	atributo	HTML	com	nome	entre	parênteses	você	também	já
conhece.	É	a	mesma	que	já	utilizamos	para	tratar	eventos	(ex:	excluir	uma	disciplina
quando	o	usuário	clicar	em	um	botão	associado	a	ela).	Então	o	trecho
	(onExcluir)="excluir($event)"		indica	o	uso	de	um	tratador	de	eventos:	o	método
	excluir()		deve	ser	chamado	passando		$event		como	parâmetro	quando	ocorrer	o	evento
	onExcluir		do	componente	ListaDeDisciplinas.	É	importante	observar	que		$event		é	uma
forma	de	acessar	os	dados	do	evento	quando	disparado	no	componente
ListaDeDisciplinas.	Nesse	caso,	do	evento		onEditar	,	o	dado	é	a	disciplina	que	deve	ser
excluída.	O	mesmo	comportamento	acontece	para	o	evento		onEditar	.
A	figura	a	seguir	procura	resumir	todas	as	informações	apresentadas	até	aqui	e	procura
demonstrar	a	interação	entre	os	componentes	App	e	ListaDeDisciplinas.
Figura	3.1.3	-	Interações	entre	os	componentes	App	e	ListaDeDisciplinas
Interação	entre	componentes
70
O	repositório	livro-componentes-editor	ainda	fornece	mais	um	nível	de	criação	de
componentes,	demonstrando	o	código	para	o	componente	EditorDeDisciplina,	que	fornece
um	formulário	para	cadastro	e	para	edição	de	uma	disciplina.	Fica	como	exercício	para
fixação	da	aprendizagem	o	estudo	do	código	desse	repositório.
[info]	Resumo	do	capítulo:
Utilizamos	Angular	CLI	para	criar	um	componente
Um	host	é	um	componente	que	utiliza	ou	inclui	um	outro,	chamado	de	guest
Um	guest	não	funciona	sem	ser	utilizado	em	um	host
O	conceito	de	Input	é	utilizado	para	o	host	fornecer	entrada	para	o	guest
O	conceito	de	Output	é	utilizado	para	o	guest	notificar	o	host	de	que	algo	(um
evento)	aconteceu
A	interação	entre	componentes	é	mais	um	recurso	que	usa	Data	binding	para
vincular	entradas	do	guest	a	atributos	do	host
Interação	entre	componentes
71
Serviços
Objetivos	do	capítulo:
demonstrar	a	modularização	de	código	utilizando	serviços
Branch:	livro-services
Conforme	a	Arquitetura	do	Angular	a	utilização	de	Serviços	tem	o	propósito	de	organizar	o
projeto	de	software	Angular,	isolando	lógica	de	negócio	e	separando-a	dos	Controllers.	Não
é	possível	afirmar	que	seja	obrigatório	utilizar	serviços,	mas	é	muito	desejável.
Na	prática	não	há	diferença	para	o	usuário	porque,	provavelmente,	utilizar	serviços	não
afetará	diretamente	o	comportamento	da	interface.	Assim,	os	benefícios	ficam	por	conta	da
melhor	organização	do	projeto	e	da	Engenharia	de	Software	para	o	projeto	que	está	sendo
desenvolvido.
Um	serviço	é	uma	classe	que	pode	ser	utilizada	por	outros	componentes	do	projeto.	Dois
detalhes	importantes	são:	o	que	diferencia	um	serviço	de	outro	tipo	de	componente	e	como
um	componente	utiliza	um	serviço.	Veremos	isso	a	seguir.
Até	o	momento	a	lógica	do	CRUD	de	disciplinas	está	toda	nos	Controllers	dos
componentes.	Isso	não	é	uma	boa	prática,	porque	é	indicado	que	a	lógica	dos	Controllers
seja	voltada	para	gerenciar	o	comportamento	da	interface,	ou	seja,	para	controlar	a
interação	entre	o	usuário	e	o	software.	Vamos	começar	criando	o	serviço	DisciplinasService
usando	Angular	CLI	e	o	comando	generate	(abreviado	por	g)	e	a	opção	service	(abreviada
por	s):
ng	g	s	Disciplinas	--spec	false	--module	App
A	linha	de	comando	cria	o	arquivo		./src/app/disciplinas.service.ts		(a	opção	--spec	false
é	utilizada	para	não	criar	um	arquivo	de	testes,	que	é	o	padrão).	A	opção	--module	App	é
utilizada	para	que	o	módulo	App	seja	modificado	para	prover	o	serviço.	Um	módulo	precisa
prover	ou	fornecer	um	serviço	para	que	ele	possa	ser	utilizado	pelos	seus	componentes.
Para	isso	ocorre	uma	alteração	na	declaração	do	módulo	App,	como	mostra	o	trecho	de
código	a	seguir:
Serviços
72
https://github.com/jacksongomesbr/angular-escola/tree/livro-services
...
import	{	DisciplinasService	}	from	'./disciplinas.service';
@NgModule({
		declarations:	[
		...
		],
		imports:	[
		...
		],
		providers:	[DisciplinasService],
		bootstrap:	[AppComponent]
})
export	class	AppModule	{
}
O	atributo		providers		está	informando	para	os	demais	componentes	do	módulo	App	que	o
serviço		DisciplinasService		está	disponível	para	uso.
O	Angular	CLI	cria	um	serviço	operacional,	mas	não	funcional,	ou	seja,	vazio.	Entretanto,	é
bom	dar	uma	olhada	no	código:
import	{	Injectable	}	from	'@angular/core';
@Injectable()
export	class	DisciplinasService	{
		constructor()	{	}
}
Novamente,	um	serviço	é	uma	classe.A	diferença	está	na	anotação		@Injectable()	.	É	ela
que	instrui	o	Angular	a	considerar	a	classe		DisciplinasService		como	um	serviço	--	pois	é,
não	há	uma	anotação	com	nome	parecido	com	@Service()	=.
Então,	vamos	adicionar	funcionalidades	nesse	serviço:
retornar	a	lista	de	disciplinas
salvar	uma	disciplina	(cadastrar	ou	excluir)
excluir	uma	disciplina
encontrar	uma	disciplina
Na	verdade,	essas	funcionalidades	já	estão	disponíveis	no	Controller	do		AppComponent	,
então	o	trabalho	agora	é	realocar	código.	Dessa	forma,	o	código	do		DisciplinasServices	
fica	mais	ou	menos	assim:
import	{Injectable}	from	'@angular/core';
import	{Disciplina}	from	'./disciplina.model';
Serviços
73
@Injectable()
export	class	DisciplinasService	{
		private	disciplinas	=	null;
		private	novo_id	=	1;
		constructor()	{
				this.disciplinas	=	[
						new	Disciplina(1,	'Língua	Portuguesa',	'O	...'),
						...
				];
		}
		todas():	Array<Disciplina>	{
				return	this.disciplinas;
		}
		salvar(id:	number,	nome:	string,	descricao:	string):	Disciplina	{
				if	(id)	{
						let	d	=	this.encontrar(id);
						if	(d)	{
								d.nome	=	nome;
								d.descricao	=	descricao;
						}	else	{
								throw	new	Error('Não	foi	possível	encontrar	a	disciplina');
						}
						return	d;
				}	else	{
						const	d	=	new	Disciplina(this.novo_id,	nome,	descricao);
						this.disciplinas.push(d);
						this.novo_id++;
						return	d;
				}
		}
		excluir(disciplina:	number	|	Disciplina)	{
				let	d	=	null;
				if	(typeof(disciplina)	===	'number')	{
						d	=	this.encontrar(disciplina);
				}	else	{
						d	=	this.encontrar(disciplina.id);
				}
				if	(d)	{
						const	i	=	this.disciplinas.indexOf(d);
						this.disciplinas.splice(i,	1);
				}	else	{
						throw	new	Error('Não	foi	possível	encontrar	a	disciplina');
				}
		}
		encontrar(arg:	number	|	string)	{
				let	d	=	null;
				if	(typeof(arg)	===	'number')	{
						d	=	this.disciplinas.filter(d	=>	d.id	===	arg);
Serviços
74
				}	else	{
						d	=	this.disciplinas.filter(d	=>	d.nome	===	arg);
				}
				if	(d	!=	null	&&	d.length	>	0)	{
						return	d[0];
				}	else	{
						return	null;
				}
		}
}
O	método		todas()		retorna	todas	as	disciplinas.
O	método		encontrar()		recebe	o	id	da	disciplina	ou	o	seu	nome,	procura	o	array
	disciplinas		e,	se	encontrar,	retorna	a	disciplina	correspondente.	Caso	contrário	retorna
	null		para	indicar	que	a	disciplina	não	foi	encontrada.	Note	a	expressão	usada	para	definir
o	tipo	do	parâmetro		arg	:		number	|	string	.	Isso	significa	que	o	método	aceita	um
parâmetro	do	tipo		number		ou		string	.	Note	também	a	utilização	do	método		filter()		para
aplicar	um	predicado	(representado	por	uma	função	seta)	para	encontrar	um	item	do	array.
A	lógica	dos	métodos		salvar()		e		excluir()		é	semelhante	à	utilizada	anteriormente	no
	AppComponente	,	com	a	diferença	de	que	não	há	interação	com	o	usuário.	É	importante
ressaltar	também	que	esses	métodos	estão	disparando	exceções	(veja	as	linhas	com		throw
new	Error(...)	)	que	devem	ser	devidamente	tratadas	nos	componentes	que	utilizarem	esse
serviço.
Já	no	Controller	do		AppComponent		a	mudança	começa	no	método	construtor:
constructor(private	disciplinasService:	DisciplinasService)	{
		this.disciplinas	=	this.disciplinasService.todas();
}
Essa	sintaxe		private	disciplinasService:	DisciplinasService		utiliza	um	recurso	importante
do	Angular	chamado	Dependency	Injection	(DI).	Por	meio	de	DI	o	Angular	cria
automaticamente	uma	instância	de		DisciplinasService		e	a	atribui	ao	atributo	privado
	disciplinasService	,	tornando	o	serviço	disponível	no	componente.	Com	isso	o	código
desse	Controller	fica	como	o	seguinte:
Serviços
75
...
import	{DisciplinasService}	from	"./disciplinas.service";
...
export	class	AppComponent	{
		editando	=	{id:	0,	nome:	'',	descricao:	''};
		...
		disciplinas	=	null;
		constructor(private	disciplinasService:	DisciplinasService)	{
				this.disciplinas	=	this.disciplinasService.todas();
		}
		salvar()	{
				try	{
						const	d	=	this.disciplinasService.salvar(this.editando.id,	
								this.editando.nome,	this.editando.descricao);
						this.salvar_ok	=	true;
						this.editando	=	{id:	0,	nome:	'',	descricao:	''};
				}	catch	(e)	{
						this.salvar_erro	=	true;
				}
		}
		excluir(disciplina)	{
				if	(this.editando	===	disciplina)	{
						alert('Você	não	pode	excluir	uma	disciplina	que	está	editando');
				}	else	{
						if	(confirm('Tem	certeza	que	deseja	excluir	a	disciplina	"'
										+	disciplina.nome	+	'"?'))	{
								try	{
										this.disciplinasService.excluir(disciplina);
										this.excluir_ok	=	true;
										this.redefinir();
								}	catch	(e)	{
										this.excluir_erro	=	true;
								}
						}
				}
		}
...
}
Perceba	como	a	lógica	da	interface	foi	mantida	e	o	código	não	possui	a	lógica	de	manipular
o	array	de	disciplinas	(consultar,	inserir,	excluir	e	encontrar	elementos),	já	que	isso	fica	a
cargo	do	serviço		DisciplinasService	.	Assim,	o	componente		AppComponent		utiliza	o	serviço
	DisciplinasService		e	vimos	como	utilizar	esse	curso	para	organizar	melhor	o	código	e
utilizar	os	padrões	de	arquitetura	do	Angular.
Serviços
76
Como	o	código-fonte	do	software	está	crescendo,	tanto	em	termos	de	volume	quanto	de
arquivos,	é	interessante	adotar	uma	abordagem	que	auxilia	ainda	mais	na	organização	de
código:	diagramas	da	UML.	A	figura	a	seguir	apresenta	o	diagrama	de	classes	do	software
até	então.
Figura	3.2.1	-	Diagrama	de	classes	do	software
O	diagrama	de	classes	apresentado	pela	figura	demonstra	relações	entre	alguns	elementos
do	software	até	então,	principalmente	com	foco	nos	controllers	dos	componentes,	no
serviço		DisciplinasService		e	nas	relações	(usa)	entre	eles.
Serviços
77
Acessando	dados	externos	de	forma
assíncrona
[info]	Objetivos	do	capítulo:
demonstrar	a	representação	de	dados	em	arquivos	JSON
demonstrar	o	uso	do	HttpClient	para	acessar	dados	externos	(arquivo	JSON)
apresentar	o	padrão	Observer	e	explicar	seu	funcionamento
apresentar	a	comunicação	entre	componentes	do	software	usando	diagrama	de
sequência	da	UML
Branch:	livro-dados-externos-json
Até	o	capítulo	anterior	(Serviços)	a	estrutura	do	software	já	começa	a	ficar	mais	modular.
Para	prosseguir	nessa	direção	uma	modificação	importante	é	trabalhar	com	fontes	de
dados.	Por	enquanto,	vamos	utilizar	um	mecanismo	simples,	mas	muito	eficiente.
O	serviço		DisciplinasService		possui	um	atributo		disciplinas	,	que	contém	um	array	de
objetos.	Embora	o	software	esteja	funcional	o	array	de	objetos	é	definido	diretamente	no
código-fonte,	o	que	pode	ser	melhorado.	A	prática	mais	adequada	é	separar	as	coisas:	de
um	lado	o	software,	do	outro	a	fonte	de	dados.
Uma	fonte	de	dados	é	um	conceito	abstrato	que	pode	ser	representado	por	um	arquivo	de
texto,	JSON	ou	um	banco	de	dados,	por	exemplo.	Aqui,	usaremos	um	arquivo	em	formato
JSON.
O	arquivo		./src/assets/dados/disciplinas.json		contém	a	lista	das	disciplinas:
[
		{
				"id":	1,
				"nome":	"Língua	Portuguesa",
				"descricao":	"..."
		},
		{
				"id":	2,
				"nome":	"Inglês",
				"descricao":	"..."
		},
		...
]
Acessando	dados	externos	de	forma	assíncrona
78
https://github.com/jacksongomesbr/angular-escola/tree/livro-dados-externos-json
Para	acessar	os	dados	de	arquivos	JSON	é	necessário	realizar	requisições	HTTP	para	um
servidor	web.	Se	você	estiver	executando	o	projeto	em	modo	de	desenvolvimento,	o
servidor	já	disponibilizado	pelo	Angular	CLI	para	desenvolvimento	será	utilizado	tanto	para
servir	o	conteúdo	do	software	quanto	fornecer	acesso	ao	arquivo	JSON.	Para	isso	o
Angular	disponibiliza	o	módulo		HttpClientModule	,	que	precisa,	primeiro,	ser	importado	no
root	module:
...
import	{HttpClientModule}	from	'@angular/common/http';
@NgModule({
		declarations:	[
				...
		],
		imports:	[
				NgbModule.forRoot(),
				BrowserModule,
				HttpClientModule,
				FormsModule
		],
		...
})
export	class	AppModule	{
}
Depois,o	serviço		DisciplinasService		precisa	ser	modificado:
...
import	{HttpClient}	from	'@angular/common/http';
import	{Observable}	from	'rxjs/Observable';
@Injectable()
export	class	DisciplinasService	{
		private	disciplinas	=	null;
		private	novo_id	=	1;
		constructor(private	http:	HttpClient)	{
		}
		carregarDados(callback)	{
				this.http.get('./assets/dados/disciplinas.json')
						.subscribe(disciplinas	=>	this.disciplinas	=	disciplinas)
						.add(callback);
		}
		...
}
Acessando	dados	externos	de	forma	assíncrona
79
A	primeira	modificação	no	código	do	serviço	é	a	injeção	de	dependência	de	um
	HttpClient	,	uma	classe	do	módulo		HttpClientModule		que	fornece	métodos	apropriados
para	realizar	requisições	HTTP	assíncronas.	A	classe		HttpClient		fornece	o	método
	get()	,	que	é	utilizado	para	realizar	uma	requisição	HTTP	GET.	O	parâmetro	informado
para	o	método		get()		é	uma	URL	que,	nesse	caso,	corresponde	ao	caminho	para	o	arquivo
	disciplinas.json	.
A	classe		HttpClient		é	usada	efetivamente	no	método		carregarDados()	,	que	aceita	como
parâmetro	uma	função	callback	que	deverá	ser	executada	quando	o	carregamento	dos
dados	for	concluído.	Esse	comportamento	é	uma	estratégia	para	carregar	os	dados	de	uma
vez,	como	um	array	de	disciplinas,	mantendo	uma	referência	para	esse	array	no	atributo
	DisciplinasSservice.disciplinas		e	também	no	atributo		AppComponent.disciplinas	.	Isso
acontece	porque	a	forma	de	acesso	à	lista	de	disciplinas,	até	o	momento,	não	permite
alterar	seu	conteúdo	de	forma	persistente,	ou	seja,	não	salva	os	dados.
Antes	de	prosseguirmos	com	a	leitura	do	código,	é	importante	detalhar	o	conceito	de
requisição	assíncrona.	A	figura	a	seguir	ilustra	esse	processo.
Figura	3.3.1	-	Ilustração	do	processo	de	requisição	assíncrona
A	figura	demonstra	que	o	Cliente	faz	uma	requisição	HTTP	para	o	Servidor	(usando	o	verbo
GET	do	HTTP)	que	busca	pelo	arquivo	solicitado.	Conforme	a	situação	o	Servidor	retorna
uma	de	duas	respostas	possíveis	para	o	Cliente:
código	200:	o	arquivo	foi	encontrado,	então	retorna	o	conteúdo	dele
código	404:	o	arquivo	não	foi	encontrador,	então	não	há	conteúdo	no	retorno
Acessando	dados	externos	de	forma	assíncrona
80
De	qualquer	forma,	um	comportamento	característico	desse	cenário	acontece:	quando	o
Cliente	faz	a	requisição	ele	continua	em	funcionamento	enquanto	aguarda	uma	resposta	do
Servidor.	Quando	a	resposta	chega	o	Cliente	é	notificado	que	isso	aconteceu	e	executa
uma	ação	específica	para	cada	tipo	de	retorno	(conforme	o	código	de	retorno	200	ou	404,
por	exemplo).	É	por	isso	que	a	requisição	é	assícrona.
Em	termos	de	código	o	método		get()		da	classe		HttpClient		não	realiza	a	requisição.	Ele
cria	um	objeto	do	tipo		Observable		(do	pacote		rxjs	)	que	implementa	um	padrão	de	projeto
chamado	Observer,	que	é	ideal	para	essa	situação	das	requisições	assíncronas.	Por	causa
desse	padrão	de	projeto,	vamos	a	uma	analogia	demonstada	pela	figura	a	seguir.
Figura	3.3.2	-	Ilustração	do	processo	de	assinatura	de	uma	revista
A	figura	ilustra	a	comunicação	entre	Cliente	e	Editora.	Depois	de	realizar	a	assinatura	o
cliente	fica	aguardando	a	Editora	publicar	uma	nova	edição	da	revista	e	enviar	um	exemplar
para	o	Cliente,	observando	esse	processo.	Enquanto	isso	acontece	o	Cliente	não	fica
parado,	mas	vai	realizando	seus	afazeres.	Quando	um	exemplar	da	nova	edição	chega,
então	o	Cliente	inicia	a	sua	leitura.
O	padrão	Observer	tem	dois	elementos	importantes:	o	publisher	(no	caso,	a	Editora)	e	o
subscriber	(no	caso,	o	Cliente).	Um	terceiro	elemento	é	importante	é	a	revista,	que
representa	o	dado	entregue	pela	Editora	para	o	Cliente.
No	contexto	do	código	o	método		get()		cria	uma	instância	de		Observable	.	Para	realizar
uma	requisição	e	realizar	uma	ação	quando	a	resposta	chega	do	servidor	é	utilizado	o
método		subscribe()	.	Por	sua	vez	o	método		subscribe()		pode	receber	dois	parâmetros:
Acessando	dados	externos	de	forma	assíncrona
81
o	primeiro	parâmetro	é	uma	função	callback	executada	quando	a	requisição	for
bem	sucedida.	Nesse	caso,	o	retorno	da	requisição	é	convertido	para	JSON	e	tratado
no	código	como	um	objeto,	representado	pelo	parâmetro	da	função	callback
o	segundo	parâmetro	é	uma	função	callback	executada	quando	a	requisição	não
for	bem	sucedida.	Nesse	caso	o	retorno	da	requisição	(se	houver)	também	é
convertido	para	JSON	e	tratado	no	código	como	um	objeto,	também	representado	pelo
parâmetro	da	função	callback.
No	caso	do	código	do	serviço		DisciplinasService		apenas	o	primeiro	parâmetro	está	sendo
utilizado,	o	que	ilustrado	pela	figura	a	seguir.
Figura	3.3.3	-	Ilustração	da	composição	de	uma	função	callback	para	o	método	subscribe\(\)
A	sintaxe	utilizada	é	conhecida	como	arrow	function	(função	seta)	e,	por	ser	uma	função,
tem	duas	partes:
parâmetros;	e
corpo.
Se	a	lista	de	parâmetros	for	vazia,	pode-se	usar	apenas		()	.
Voltando	ao	código	do	serviço		DisciplinasService		a	função	callback	de	sucesso	para	a
chamada	de		subscribe()		atribui	o	parâmetro	disciplinas	(a	lista	de	disciplinas	retornada
pelo	servidor	já	em	formato	de	objetos)	para	o	atributo	da	classe	de	mesmo	nome.
Para	finalizar	a	leitura	do	código	do		DisciplinasService		há	mais	um	recurso	importante
sendo	utilizado.	O	método		carregarDados()		recebe	como	parâmetro	uma	função	callback.
O	método	cria	uma	instância	de		Observable		e	chama	o	método		subscribe()	.	Como	o
objetivo	desse	método	é	executar	a	função	callback	informada	como	parâmetro	quando	a
requisição	HTTP	for	concluída	e	os	dados	estiverem	disponíveis,	é	feita	uma	chamada	para
a	função		add()	,	informando	como	parâmetro	a	função	callback.
Para	usar	o	serviço		DisciplinasService		o		constructor()		do	Controller		AppComponent	
comporta-se	da	seguinte	forma:
Acessando	dados	externos	de	forma	assíncrona
82
constructor(private	disciplinasService:	DisciplinasService)	{
		this.disciplinasService.carregarDados(
				()	=>	this.disciplinas	=	this.disciplinasService.todas()
		);
}
Perceba	que	a	chamada	para		carregarDados()		informa	uma	arrow	function	como
parâmetro	(a	callback).
Para	finalizar	esse	capítulo,	a	figura	a	seguir	resume	e	ilustra	os	conceitos	apresentados,
indicando	a	sequência	de	passos	da	comunicação	entre	os	componentes.
Figura	3.3.4	-	Diagrama	de	sequência	do	software,	demonstrando	a	interação	entre
AppComponent,	DisciplinasService	e	Servidor	HTTP
Se	necessário	analise	a	sequência	do	diagrama	mais	de	uma	vez,	acompanhado	do	código-
fonte.
Acessando	dados	externos	de	forma	assíncrona
83
Acessando	dados	de	uma	API	HTTP
[info]	Objetivos	do	capítulo:
reforçar	o	conceito	de	requisição	assícrona	utilizando	a	classe	HttpClient
demonstrar	a	utilização	da	classe	HttpClient	para	acessar	dados	de	uma	API
HTTP	REST
demonstrar	como	lidar	com	situações	de	sucesso	e	erro	ao	lidar	com	requisições
assíncronas
Branch:	livro-dados-externos-api-http-rest
O	capítulo	Acessando	dados	externos	de	forma	assíncrona	apresentou	como	utilizar
recursos	do	Angular	para	acessar	dados	de	um	arquivo	JSON.	Entretanto,	a	limitação
daquela	abordagem,	embora	seja	suficiente	para	várias	situações,	precisa	de	uma
alternativa	mais	completa,	que	permita	a	persistência	dos	dados.	Uma	solução	para	essa
questão	é	utilizar	uma	API	HTTP.	Vamos	utilizar	uma	API	HTTP	REST	disponível	no
repositório	angular-escola-api.	Este	capítulo	não	apresenta	detalhes	de	como	fazer	essa
API	funcionar,	mas	vez	ou	outras	algumas	informações	serão	apresentadas.
Iniciando	o	servidor	web	da	API
Depois	de	clonar	o	repositório	da	API	execute	o	comando:
npm	start
Após	alguns	instantes	o	servidor	estará	disponível	para	aceitar	requisições.	Se	quiser	testar
a	API	diretamente	pelo	browser	acesse	o	endereço	da	API,	indicado	na	mensagem	de
saída	do	comando	anterior.
Modificando	o	DisciplinasService
Como	você	já	sabe	o	serviço	DisciplinasService	do	capítulo	anterior	está	fazendo
requisições	para	o	servidor	web	de	desenvolvimento	em	busca	do	arquivo	JSON	que
contém	a	lista	das	disciplinas.	Para	consultar	a	API	a	primeira	alteração	está	na	estrutura	doserviço:
remover	todos	os	atributos
Acessando	dados	de	uma	API	HTTP
84
https://github.com/jacksongomesbr/angular-escola/tree/livro-dados-externos-api-http-rest
https://github.com/jacksongomesbr/angular-escola-api
adicionar	o	atributo		API_URL		com	o	valor		"http://localhost:3000"		(que	é	o	endereço
padrão	do	servidor	web	da	API)
remover	o	método		carregarDados()	
alterar	o	código	dos	métodos		todas()	,		salvar()	,		excluir()		e		encontrar()	.
Assim,	o	serviço	DisciplinasService	fica	dessa	maneira:
...
@Injectable()
export	class	DisciplinasService	{
		API_URL	=	'http://localhost:3000';
		constructor(private	http:	HttpClient)	{	}
		todas()	{
				return	this.http.get(this.API_URL	+	'/disciplinas');
		}
		salvar(id:	number,	nome:	string,	descricao:	string)	{
				const	disciplina	=	{nome:	nome,	descricao:	descricao};
				if	(id)	{
						return	this.http.patch(this.API_URL	+	'/disciplinas/'	+	id,	disciplina);
				}	else	{
						return	this.http.post(this.API_URL	+	'/disciplinas',	disciplina);
				}
		}
		excluir(disciplina:	number	|	Disciplina)	{
				let	id;
				if	(typeof(disciplina)	===	'number')	{
						id	=	disciplina;
				}	else	{
						id	=	disciplina.id;
				}
				return	this.http.delete(this.API_URL	+	'/disciplinas/'	+	id);
		}
		encontrar(arg:	number)	{
				return	this.http.get(this.API_URL	+	'/disciplinas/'	+	arg);
		}
}
O	método		todas()		utiliza	o	método		get()		do		HttpClient		para	realizar	uma	requisição
GET	para	a	URL		/disciplinas		(a	partir	da	URL	da	API)	para	retornar	a	lista	das	disciplinas.
A	API	retorna	um	array	de	objetos	com	os	atributos:		id	,		codigo	,		nome		e		descricao	.	Da
mesma	forma	como	antes	(no	antigo	método		carregarDados()	)	os	dados	são	convertidos
para	objetos	automaticamente	quando	a	requisição	HTTP	for	realizada	--	lembre-se	que	é
preciso	chamar	o	método		subscribe()		para	isso.
Acessando	dados	de	uma	API	HTTP
85
O	método		salvar()		recebe	os	dados	de	uma	disciplina	como	parâmetro	(	id	,		nome	,
	descricao	),	define	um	objeto	chamado		disciplina		com	os	valores	dos	parâmetros	e
checa	o	valor	do	parâmetro		id		para	saber	se	é	necessário:
alterar:	nesse	caso	o		id		possui	algum	valor	e	é	feita	uma	requisição	PATCH	para	a
URL	da	disciplina	na	API,	por	exemplo		/disciplinas/1	,	por	meio	do	método		patch()	
da	classe		HttpClient	;	ou
cadastrar:	nesse	caso	o		id		não	possui	valor	(ex:		null	)	e	é	feita	uma	requisição
POST	para	a	URL		/disciplinas		da	API	por	meio	do	método		post()		da	classe
	HttpClient	.
Perceba	que	nos	dois	casos	o	segundo	parâmetro	da	chamada	dos	métodos		patch()		e
	post()	é	o	objeto		disciplina	.	Isso	é	necessário	porque	a	API	espera	que	os	dados
estejam	em	formato	JSON,	o	que	também	é	feito	automaticamente	pelo	Angular	(converte	o
objeto		disciplina		para	sua	representação	em	JSON	ao	enviar	os	dados	para	a	API).	Além
disso,	da	mesma	forma	como	acontece	com	o	método		get()		da	classe		HttpClient	,	a
requisição	HTTP	só	acontece,	efetivamente,	quando	é	chamado	o	método		subscribe()	.
O	método		excluir()		recebe	o	parâmetro		disciplina	,	que	pode	ser	um	número	(o
identificador	da	disciplina)	ou	o	objeto	que	representa	a	disciplina.	Com	base	no	tipo	do
parâmetro	o	código	obtém	o	identificador	da	disciplina	e	o	utiliza	para	fazer	uma	requisição
DELETE	para	a	URL	da	API	que	representa	a	disciplina	(ex:		/disciplinas/1	).	Isso	é	feito
por	meio	de	uma	chamada	para	o	método		delete()		da	classe		HttpClient	.
Por	último,	o	método		encontrar()		recebe	o	identificador	da	disciplina	como	parâmetro	e	faz
uma	requisição	GET	para	a	URL	da	API	que	representa	a	disciplina	por	meio	do	método
	get()		da	classe		HttpClient	.
Modificando	o	AppComponent
As	alterações	mais	expressivas	acontecem	no	Controller	do		AppComponent		para	usar	o
serviço		DisciplinasService	.	Primeiro,	o		constructor()		chama	o	novo	método
	atualizarLista()	:
Acessando	dados	de	uma	API	HTTP
86
constructor(private	disciplinasService:	DisciplinasService)	{
		this.atualizarLista();
}
atualizarLista()	{
		this.disciplinasService.todas()
				.subscribe(disciplinas	=>	{
						this.disciplinas	=	disciplinas;
						this.status_lista	=	true;
				},	()	=>	this.status_lista	=	false);
}
O	método		atualizarLista()		chama	o	método		todas()		do		DisciplinasService	.	Perceba
que,	porque	o	retorno	do	método	é	um		Observable	,	é	possível	chamar	o	método
	subscribe()		logo	em	seguida.	Como	de	costume,	uma	figura	para	explicar	isso	em	partes:
Figura	3.4.1	-	Ilustração	da	estrutura	de	callback	de	sucesso	e	erro
A	figura	destaca,	na	cor	verde,	o	código	da	callback	de	sucesso.	Lembre-se	que	a	callback
de	sucesso	executa	se	a	requisição	para	a	API	for	bem	sucedida	(código	de	retorno	igual
200).	Nesse	caso	a	arrow	function	tem	o	parâmetro	disciplinas	e	o	corpo	da	função	faz:
atribui		disciplinas		para		this.disciplinas		(a	lista	das	disciplinas,	que	o	Template
utiliza)
atribui		true		para		this.status_lista		(um	valor	de	controle	utilizado	no	Template)
Ainda	na	figura,	a	cor	vermelha	destaca	a	callback	de	erro.	A	callback	de	erro	executa	se	a
requisição	para	a	API	não	for	bem	sucedida	(código	de	retorno	diferente	de	200,	como	404
ou	500).	A	arrow	function	não	tem	parâmetro	e	seu	corpo	atribui		false		para
Acessando	dados	de	uma	API	HTTP
87
	this.status_lista	.
O	método		salvar()		chama	o	método		salvar()		do		DisciplinasService	:
salvar()	{
		this.disciplinasService.salvar(this.editando.id,	
					this.editando.nome,	this.editando.descricao)
				.subscribe(disciplina	=>	{
								this.redefinir();
								this.salvar_ok	=	true;
								this.atualizarLista();
						},
						()	=>	{
								this.redefinir();
								this.salvar_erro	=	true;
						}
				);
}
Nesse	caso	a	callback	de	sucesso,	que	indica	que	os	dados	foram	salvos	na	API,	faz	com
que	a	tela	apresente	uma	mensagem	de	sucesso	e	a	lista	de	disciplinas	é	atualizada	(para
mostrar	os	novos	dados	das	disciplinas).	Note	também	que	a	callback	recebe	o	parâmetro
	disciplina	,	que	não	é	utilizado,	mas	que	é	retornado	pela	API	contendo	os	dados	do
objeto.	No	caso	da	API	que	estamos	utilizando,	se	for	feita	uma	requisição	POST	o	objeto
retornado	pela	API	contém	um	atributo	id	cujo	valor	é	gerado	automaticamente,	de	forma
incremental	(lembra	que	já	precisamos	controlar	isso	manualmente?).	No	caso	da	callback
de	erro,	o	código	faz	com	que	a	tela	apresente	uma	mensagem	de	erro.
Os	demais	métodos,		excluir()		e		editar()	,	utilizam,	respectivamente,	os	métodos
	excluir()		e		encontrar()		da	classe		DisciplinasService	.	Fica	como	exercício	interpretar	o
código.
A	execução	do	software	no	browser	não	é	muito	diferente	do	capítulo	anterior.	Entretanto,
como	estamos	utilizando	uma	API	HTTP	REST,	é	importante	tomar	certos	cuidados.	Por
exemplo,	se,	por	algum	motivo,	não	for	possível	acessar	a	API,	é	interessante	apresentar
uma	mensagem	de	erro	na	tela.	A	figura	a	seguir	ilustra	essa	situação.
Acessando	dados	de	uma	API	HTTP
88
Figura	3.4.2	-	Execução	do	software	no	browser	demonstrando	mensagem	de	erro	de
conexão	com	a	API	HTTP	REST
Caso	contrário,	se	a	API	estiver	acessível	e	tudo	estiver	ocorrendo	como	esperado,	a
interface	continua	mostrando	os	dados	e	permitindo	interação	com	o	usuário	normalmente.
Para	finalizar	o	capítulo,	um	diagrama	de	sequência	demonstrando	a	interação	entre
	AppComponent	,		DisciplinasService		e	o	Servidor	HTTP	da	API	quando	é	executado	o
método		atualizarLista()		do		AppComponent	.
Acessando	dados	de	uma	API	HTTP
89
Figura	3.4.3	-	Diagrama	de	sequência	demonstrando	a	interação	entre	AppComponent,
DisciplinasService	e	Servidor	HTTP	quando	é	chamado	o	método	atualizarLista()	do
AppComponent
O	diagrama	de	sequência	demonstra	as	interações	desde	a	chamada	do	método		todas\
(\)		do		DisciplinasService		até	o	tratamento	do	retorno	do	Servidor	HTTP	(ou	erro).
[info]	Resumo	do	capítulo:
A	classe		HttpClient		é	muito	útil	para	acessar	dados	via	requisições	HTTP
A	classe		HttpClient		pode	ser	utilizada	para	comunicação	com	uma	API	HTTP
REST
A	utilização	de	serviçospara	organização	do	código	é	um	recurso	para	melhoria
da	arquitetura	do	software
Acessando	dados	de	uma	API	HTTP
90
Rotas
[info]	Objetivos	do	capítulo:
apresentar	o	conceito	de	rotas
demonstrar	a	utilização	de	rotas	para	apresentação	de	componentes
demonstrar	a	diferença	da	estrutura	de	software	desse	capítulo	para	os	capítulos
anteriores
demonstrar	como	o	Angular	implementa	e	utiliza	o	conceito	de	rotas
demonstrar	a	utilização	de	parâmetros	de	rota
Branch:	livro-rotas
Os	capítulos	anteriores	demonstraram	como	trabalhar	com	elementos	principais	da
arquitetura	do	Angular,	principalmente	componentes	e	serviços.	Esses	elementos	têm	o
objetivo	de	compor	a	arquitetura	de	um	software	desenvolvido	em	Angular	e,	como	visto,	há
vários	recursos	que	permitem	a	interação	entre	eles.
Este	capítulo	apresenta	outro	recurso	de	arquitetura	de	software	desenvolvido	em	Angular
que,	na	verdade,	aumenta	a	usabilidade	do	software.
Antes	de	apresentar	a	parte	técnica	é	importante	lidar	com	alguns	conceitos.
URI,	URL	e	URN
URI	(Uniform	Resource	Identifier)	é	um	identificador	de	um	recurso.	A	sintaxe	desse
identificador	é:
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
Onde	os	elementos	entre	[]	são	opcionais	e:
scheme:	representa	o	protocolo	ou	o	contexto;
user	e	password:	representam	as	credenciais	do	usuário;
host:	representa	o	identificador	do	dispositivo	que	contém	o	recurso;
port:	representa	o	número	da	porta	do	dispositivo;
path:	representa	o	caminho	do	recurso;
query:	uma	cadeia	de	caracteres	que	representa	parâmetros	de	URL,	um	conjunto	de
pares		chave=valor		separados	por		&	;	e
fragment:	uma	cadeia	de	caracteres	com	formato	dependente	do	contexto.
Rotas
91
https://github.com/jacksongomesbr/angular-escola/tree/livro-rotas
A	figura	a	seguir	ilustra	um	URI	e	a	sua	composição:
O	URI	identifica	um	recurso	disponível	na	internet,	mais	especificamente	um	repositório	do
Github.	Provavelmente	você	já	conhece	isso	e	pode	ser	que	use	os	termos	endereço	e
URL.	Você	não	está	errado.	URL	é	a	forma	mais	comum	de	URI	na	internet.	URL	(Uniform
Resource	Locator)	é	um	endereço	de	um	recurso	na	internet.	Além	disso,	URL	é	a	forma
mais	comum	de	criar	_links	_entre	páginas	web	e	incorporar	uma	imagem	em	uma	página
web,	por	exemplo.
URN	(Uniform	Resource	Name)	é	o	nome	de	um	recurso	em	um	contexto	específico.	Por
exemplo:	o	ISBN	(International	Standard	Book	Number)	de	uma	edição	de	"Romeu	e
Julieta",	de	William	Shakespeare,	é	0-486-27557-4;	seu	URN	poderia	ser	urn:isbn:0-486-
2557-4.
Voltando	para	URL	e	o	contexto	da	internet,	os	browsers	geralmente	fornecem	uma	barra
de	endereço,	por	meio	da	qual	o	usuário	indica	qual	URL	deseja	acessar,	por	exemplo	a
URL	de	uma	página	web.	A	partir	do	momento	que	o	browser	acessa	uma	página	web	ele
passa	a	armazenar	o	primeiro	endereço	acessado	e	os	demais	endereços	que	forem
acessados	por	meio	de	cliques	em	links.
Esse	é,	provavelmente,	o	formato	mais	intuitivo	e	o	mais	utilizado	para	acessar	páginas
web.	Justamente	por	isso	é	necessário	repensar	a	forma	como	o	aplicativo	desenvolvido	em
Angular	não	apenas	entrega	conteúdo	para	o	usuário	mas	também	como	permite	que	o
usuário	o	acesse.
Rotas
Uma	rota	está	diretamente	relacionada	a	URL,	ou	seja,	também	funciona	como	um
localizador	de	um	recurso.	A	diferença	é	que	acrescenta	a	possibilidade	de	utilizar
parâmetros	de	rota.	Por	exemplo:	considere	um	site	de	notícias	noticias.to	que	permite
acessar	a	notícia	"Governo	paga	salarios	de	servidores",	cujo	identificador	é	7899,	está	na
categoria	"política"	e	foi	publicada	em	20/12/2017,	por	meio	do	URL:
https://noticias.to/noticias/politica/2017/12/20/governo-paga-salarios-de-servidores/7
899
Há	informações	no	URL	que	pertencem	à	notícia	e	mudam	de	uma	notíca	para	outra:
categoria:	politica
Rotas
92
ano:	2017
mês:	12
dia:	20
titulo:	governo-paga-salarios-de-servidores
identificador:	7899
Analisando	URLs	de	outras	notícias	alguém	poderia	chegar	à	conclusão	de	que	há	um
padrão:
/noticias/categoria/ano/mes/dia/titulo/identificador
Independentemente	de	possuir	parâmetros	de	rota,	uma	rota	é	um	padrão.	Cada	uma
dessas	informações	(categoria,	ano,	mes,	dia,	titulo,	identificador),	que	muda	de	uma	notícia
para	outra,	pode	ser	representada	como	um	parâmetro	de	rota.
A	implementação	desse	conceito	pode	variar	entre	frameworks,	mas	provavelmente	as
mesmas	funcionalidades	estão	disponíveis:
definir	uma	rota	(e,	opcionalmente,	usar	parâmetros	de	rota)
identificar	valores	dos	parâmetros	de	rota
Além	disso,	como	URLs	são	localizadores	de	recursos,	rotas	também	servem	para	esse
propósito,	ou	seja,	uma	rota	está	associada	algum	recurso	e	é	uma	forma	de	acessá-lo.
Estrutura	do	software
Aqui	fazemos	uma	pequena	pausa	no	assunto	de	rotas	para	entender	a	estrutura	do
software	construído	nesse	capítulo,	ilustrada	pela	figura	a	seguir.
Rotas
93
Figura	3.5.1	-	Estrutura	de	classes	do	software
Como	mostra	a	figura	a	estrutura	do	software	contém:
um	módulo:		AppModule	
quatro	componentes:		AppComponent	,		HomeComponent	,		ListaDeDisciplinasComponent		e
	EditorDeDisciplinasComponent	
um	serviço:		DisciplinasService	
	AppComponent		é	utilizado	como	componente	do	bootstrap	do	módulo		AppModule	.
	HomeComponent		é	o	primeiro	componente	visualizado	pelo	usuário,	representando	a	tela
inicial	do	aplicativo.
	ListaDeDisciplinasComponent		apresenta	a	lista	de	disciplinas	e	também	permite	que	o
usuário	exclua	uma	disciplina	e	acesse	a	tela	de	cadastro	e	edição	de	uma	disciplina.
	EditorDeDisciplinaComponent		funciona	como	um	editor	de	disciplinas,	servindo	tanto	para
cadastrar	quanto	para	editar	uma	disciplina.
Até	o	capítulo	anterior	também	havia	uma	estrutura	de	classes	semelhante	a	essa.
Entretanto,	o		AppComponent		continha	a	lógica	de	gerenciamento	dos	dados	e	incluía	os
componentes		ListaDeDisciplinasComponent		e		EditorDeDisciplinaComponent	,	utilizando	input
e	output	para	entregar	e	receber	dados	deles.	Aqui	neste	capítulo,	com	o	recurso	de	rotas,
o	resultado	é	diferente:
Rotas
94
	AppComponent		não	tem	a	lógica	para	gerenciar	dados	de	disciplinas
	ListaDeDisciplinasComponent		não	tem	input	ou	output,	pois	interage	diretamente	com	o
	DisciplinasService	
	EditorDeDisciplinaComponent		não	tem	input	ou	ouptut,	interage	diretamente	com	o
	DisciplinasService		e	usa	o	recurso	parâmetros	de	rota	para	saber	quando	é
necessário	editar	uma	disciplina	(e	qual	deve	ser	editada)	ou	cadastrar	uma	disciplina.
Rotas	no	Angular
Controlar	a	visibilidade	de	componentes	é	uma	tarefa	simples.	Isso	pode	ser	consideguido,
por	exemplo,	utilizando	as	diretivas		ngIf		e		hidden	.	Entretanto,	a	complexidade	aumenta
na	proporção	da	quantidade	de	componentes	ou	da	complexidade	das	interações	com	o
usuário.	Por	isso	o	Angular	implementa	o	conceito	de	rotas	de	uma	maneira	bastante	útil.
Para	usar	rotas	é	possível	definí-las	das	seguintes	formas:
no	root	module
no	feature	module
no	módulo	de	rotas
Nesse	momento	vamos	usar	a	primeira	abordagem.	Modifique	o	arquivo
	./src/app/app.module.ts	:
Rotas
95
...
import	{RouterModule,	Routes}	from	'@angular/router';
...	(imports	dos	componentes)
const	appRoutes:	Routes	=	[
		{path:	'disciplinas',	component:	ListaDeDisciplinasComponent},
		{path:	'disciplinas/:id',	component:	EditorDeDisciplinaComponent},
		{path:	'',	component:	HomeComponent,},
		{path:	'**',	component:	PaginaNaoEncontradaComponent}
];
@NgModule({
		declarations:	[
				AppComponent,
				ListaDeDisciplinasComponent,
				EditorDeDisciplinaComponent,
				HomeComponent,
				PaginaNaoEncontradaComponent
		],
		imports:	[
				RouterModule.forRoot(
						appRoutes,
						{enableTracing:	true}	
				),
				...
		],
		providers:	[DisciplinasService],
		bootstrap:	[AppComponent]
})
export	class	AppModule	{
}
A	primeira	coisa	a	destacar	é	a	variável		appRoutes	,	do	tipo		Routes	.	O	pacote
	@angular/router		fornece	o	módulo		RouterModule		e	a	classe		Routes	.	Na	prática	a	variável
	appRoutes		recebe	um	array	no	qual	cada	item	é	um	objeto	com	dois	atributos:path	:	representa	a	rota	para	o	componente;	e
	component	:	representa	o	componente	associado	à	rota.
A	primeira	rota,		disciplinas	,	está	associada	ao	componente		ListaDeDisciplinasComponent	.
A	segunda	rota,		disciplinas/:id	,	está	usando	um	parâmetro	de	rota.	A	sintaxe	do
Angular	para	parâmetro	de	rotas	é	usar	o	sinal	de	dois	pontos	seguido	do	nome	do
parâmetro.	Nesse	caso	o	parâmetro	chama-se		id	.	A	rota	está	associada	ao	componente
	EditorDeDisciplinaComponent	.
Rotas
96
A	terceira	e	a	quarta	rotas	têm	um	comportamento	especial.	A	terceira	rota	é	uma	string
vazia	e	está	associada	ao	componente		HomeComponent	.	Isso	significa	que	essa	é	a	rota
padrão.	A	quarta	rota	é		**	,	associada	ao	componente		PaginaNaoEncontradaComponent	.	Isso
significa	um	atalho	para	o	seguinte	comportamento:	se	o	usuário	fornecer	uma	rota	não
definida,	leve	até	o	componente		PaginaNaoEncontradaComponent	.
Por	fim,	as	rotas	são	inseridas	no	módulo	por	meio	de	um	elemento	do	array		imports	
resultante	de	uma	chamada	para	o	método		RouterModule.forRoot()	,	passando	como
parâmetro	o	array	de	rotas,	o	a	variável		appRoutes	.
Quando	o	software	é	executado	o	Angular	busca	uma	combinação	entre	a	URL	fornecida
no	browser	e	as	rotas	definidas	no	módulo.	Isso	é	feito	de	cima	para	baixo,	procurando	no
array		appRoutes	.	Ao	encontrar	uma	rota	correspondente,	o	Angular	cria	uma	instância	do
componente	e	a	apresenta.	A	figura	a	seguir	ilustra	esse	processo.
Figura	3.5.2	-	Processo	de	interpretação	da	URL	em	busca	em	uma	rota	e	do	seu
componente
O	modo	de	comparação	entre	a	URL	no	browser	e	o	caminho	da	rota	é	muito	interessante.
A	forma	de	comparação	considera	se	o	caminho	da	rota	combina	com	o	final	da	URL	do
browser.	A	figura	ilustra	a	busca	por	uma	rota	correspondente	à	URL
	http://localhost:4200		e	interrompe	o	processo	quando	encontra	a	primeira
correspondência.	Nesse	mesmo	sentido	se	a	URL	no	browser	for
	http://localhost:4200/disciplinas		o	Angular	encontra	a	rota		disciplinas	.	E	assim	por
diante.
Voltando	à	figura	a	URL	indica	o	que	é	conhecido	como	raiz	do	site.	É	opcional	que	a	URL
termine	com		/	.
Outra	característica	importante	desse	processo	é	a	ordem	das	rotas.	Como	disse,	o	Angular
procura	pela	rota	que	combina	com	o	final	da	URL,	assim,	se	a	rota	padrão	estiver	no	início
da	lista	das	rotas,	então	o	Angular	sempre	a	encontrará.	Da	mesma	forma,	se	não	encontrar
uma	rota	correspondente	o	Angular	vai	até	a	rota		**	.
Shell	component
Rotas
97
Quando	o	Angular	identifica	a	rota	e	o	componente	associado	a	ela	é	necessário	apresentá-
lo	(lembre-se	que	o	componente	é,	provavelmente,	visual).	Assim,	ao	utilizar	rotas	o	Angular
requer	que	o	módulo	(nesse	caso	o		AppModule	)	utilize	um	componente	como	shell,	o	que
significa	que	o	Template	do	componente	precisa	indicar	onde	outros	componentes	serão
apresentados.	Para	isso	o	Angular	utiliza	duas	informações:
qual	o	componente	o	módulo	declara	como		bootstrap		(o		AppComponent		é	o	shell
component)
onde	está	o	elemento		router-outlet		no	Template	do		AppComponent	
A	figura	a	seguir	ilustra	esse	processo,	considerando	que	a	URL	no	browser	é
	http://localhost:4200	.
Figura	3.5.3	-	Utilização	do	shell	component	e	combinação	do	seu	Template	com	o
Template	do	componente	associado	à	rota
Como	mostra	a	figura,	o	Angular	combina	o	Template	do		AppComponent		com	o	Template	do
	HomeComponent		para	gerar	uma	saída	HTML	[unificada]	para	o	browser.	Importante	perceber
que	tudo	o	que	está	antes	e	depois	do	elemento		router-outlet		é	mantido	na	saída.	Por
isso	o	Angular	usa,	em	conjunto,	a	descoberta	da	rota	e	do	componente	associado	e	o
conteúdo	do	shell	component.
Parâmetros	de	rota
No	caso	do		EditorDeDisciplinaComponent		há	uma	lógica	no	funcionamento	do	componente
que	depende	de	identificar,	conforme	a	rota,	se	é	necessário	editar	uma	disciplina	existente
(e	qual	é	essa	disciplina)	ou	se	é	necessário	cadastrar	uma	disciplina.	Obviamente,	nesse
caso,	o	componente	executa	duas	funções	(cadastrar	e	editar	disciplina).	Uma	alternativa	é
utilizar	dois	componentes,	cada	qual	com	uma	função	diferente.
Rotas
98
A	rota		disciplinas/:id	,	como	já	visto,	possui	um	parâmetro	de	rota	chamado		id	.	Obter
o	valor	desse	identificador	da	disciplina	na	URL	é	uma	tarefa	importante	desse	processo	de
lidar	com	rotas	no	Angular.	Para	fazer	isso,	o	componente		EditorDeDisciplinaComponent	
possui	o	atributo		route	,	uma	instância	de		ActivatedRoute	,	como	mostra	o	trecho	de
código	a	seguir.
import	{Component,	EventEmitter,	Input,	OnInit,	Output}	from	'@angular/core';
import	{ActivatedRoute,	Router}	from	'@angular/router';
...
export	class	EditorDeDisciplinaComponent	implements	OnInit	{
		...
		constructor(private	route:	ActivatedRoute,
														private	router:	Router,
														private	disciplinasService:	DisciplinasService)	{
		}
		ngOnInit()	{
				const	id	=	this.route.snapshot.paramMap.get('id');
				if	(id	==	'cadastrar')	{
						this.disciplina	=	new	Disciplina(null,	null,	null);
						this.status	=	null;
				}	else	{
						this.disciplinasService.encontrar(parseInt(id))
								.subscribe(...);
				}
		}
		...
}
Como	o	componente	implementa	a	interface		OnInit	,	o	código	do	método		ngOnInit()		é
responsável	por:
identificar	o	valor	do	parâmetro	de	rota:	isso	é	feito	por	meio	de	uma	chamada	para
o	método		route.snapshot.paramMap.get()	.	O	parâmetro	para	o	método		get()		é	o
nome	do	parâmetro	de	rota	desejado
tratar	o	valor	do	parâmetro	de	rota:	o	valor	retornado	por		get()		é	do	tipo		string	.
Se	o	valor	do	parâmetro	de	rota	for	igual	a		'cadastrar'		então	o	componente	opera	no
modo	de	cadastro	de	disciplina;	caso	contrário,	o	código	faz	uma	chamada	ao	método
	disciplinasService.encontrar()	,	passando	como	parâmetro	o	valor	do	parâmetro	de
rota	convertido	para	o	tipo		number	,	usando	a	função		parseInt()	,	então	o	componente
entra	no	modo	de	edição	de	uma	disciplina.
O	método		ngOnInit()		é	executado	pelo	Angular	no	início	do	processo	de	instanciar	o
componente	e	apresentá-lo	na	tela.
Navegação
Rotas
99
A	navegação	é	o	recurso	que	permite	mudar	de	uma	rota	para	outra.	Isso	pode	ser	feito	por
meio	de	uma	ação	do	usuário	(por	exemplo,	quando	ele	clica	em	um	link)	ou	via	código.
A	navegação	por	meio	de	link	utiliza	o	elemento		a		e	o	atributo		routerLink	,	como	mostra	o
Template	do		HomeComponent	:
<h2>Gerenciador	de	dados	escolares</h2>
<p>
				<a	routerLink="/disciplinas"	class="btn	btn-primary">
								Gerenciar	disciplinas
				</a>
</p>
O	atributo		routerLink		tem	o	valor		/disciplinas	,	o	que	significa	que	quando	o	usuário
clicar	no	link	ocorrerá	uma	navegação	para	a	rota		disciplinas	.	É	importante	destacar	que,
embora	a	definição	da	rota	não	inclua	uma	barra	no	início	do	caminho,	o	mesmo	não
acontece	aqui,	com	o	link.	É	como	determinar	que	o	link	sempre	considera	a	raiz	do	site
(usando	um	caminho	absoluto).
Na	lista	de	disciplinas	há	um	botão	que	permite	editar	uma	disciplina.	No	clique	do	botão	há
uma	chamada	para	a	função		editar()	,	cujo	trecho	de	código	é	apresentado	a	seguir.
...
export	class	ListaDeDisciplinasComponent	implements	OnInit	{
		...
		constructor(private	disciplinasService:	DisciplinasService,	
				private	router:	Router)	{
		}
		editar(disciplina)	{
				this.router.navigate(['disciplinas',	disciplina.id]);
		}
}
O		ListaDeDisciplinasComponent		possui	o	atributo		router	,	do	tipo		Router	.	A	classe
	Router		fornece	o	método		navigate()	,	que	é	utilizado	para	fazer	a	navegação	via	código.
O	parâmetro	para	o	método		navigate()		é	um	array	cujos	elementos	representam	partes	de
uma	URL.	No	caso	do	método		editar()		os	parâmetros	são:		'disciplinas'		e
	disciplina.id	.	O	Angular	utiliza	esses	elementos	para	gerar,	por	exemplo,	a	URL
	/disciplinas/1		para	editar	a	disciplina	com	identificador	1.
Padrão	de	trabalho	(workflow)
Rotas
100
Lidar	com	rotas	no	Angular	é	um	processo	simples,	mas	que	aumenta	de	complexidade	na
proporção	da	quantidade	de	componentes,	módulos	ou	na	complexidade	da	arquiteturado
software.	Entretanto,	lidar	com	esse	processo	contém	alguns	passos	padrão	(supondo	que
o	projeto	já	tenha	iniciado	e	adote	a	mesma	estrutura	do	Angular	CLI):
1.	 criar	componente:	a	primeira	coisa	a	fazer	é	criar	o	componente	desejado.	Como	é
importante	conduzir	esse	processo	de	forma	iterativa,	não	se	preocupe	em	construir	o
componente	por	inteiro,	deixe-o	como	criado	pelo	Angular	CLI;
2.	 definir	rotas:	depois,	defina	as	rotas	(utilizando,	por	exemplo,	o	root	module,	como
visto	neste	capítulo);
3.	 implementar	a	lógica	de	negócio	em	um	serviço:	ao	utilizar	serviços,	implemente	a
lógica	de	negócio	do	serviço;	e
4.	 implementar	lógica	do	componente	e	usar	o	serviço:	por	fim,	melhore	a	lógica	do
componente,	fornecendo	código	para	a	lógica	da	interface	e	da	lógica	de	negócio,	e
utilize	o	serviço.
Adotar	esse	padrão	de	trabalho	pode	tornar	o	desenvolvimento	mais	simples	e	rápido,	bem
como	reduzir	a	quantidade	de	erros	e	permitir	a	identificação	dos	erros	de	forma	mais	ágil.
[info]	Resumo	do	capítulo
Rotas	servem	como	recurso	para	integrar	componentes	ao	mecanismo	de
navegação	do	browser,	que	já	é	conhecido	pelos	usuários
É	possível	identificar	valores	dos	parâmetros	de	rota	utilizando	a	classe
	ActivatedRoute	
É	possível	fazer	navegação	entre	as	rotas	usando	o	atributo		routerLink		e	a
classe		Router	
O	shell	component	é	um	componente	utilizado	para	fornecer	uma	estrutura
padrão	para	os	componentes	de	um	módulo
O	shell	component	utiliza	o	elemento		router-outlet	
O	Angular	combina	o	Template	do	shell	component	e	do	componente	associado	a
uma	rota	para	gerar	uma	saída	comum	para	o	browser
Rotas
101
Feature-modules
[info]	Objetivos	do	capítulo:
demonstrar	a	modularização	do	software	utilizando	módulos
criando	componentes	em	módulos
importando	módulos
descrevendo	rotas	em	módulos
Branch:	livro-modulos-admin-publico-shared
Todos	os	capítulos	anteriores	estão	convergindo	para	um	ponto:	utilizar	recursos	do	Angular
para	melhorar	a	arquitetura	e	estrutura	do	software.	A	figura	a	seguir	dá	uma	ideia	mais
visual	disso.
Figura	3.6.1	-	Arquitetura	do	software	demonstrando	interações	entre	módulos	e	API
O	funcionamento	esperado	é	o	seguinte:
a	interface	gráfica	é	representada	pelo	arquivo		src/index.html	
	AppModule	,	que	é	o	root	module,	é	apresentado	na	interface	gráfica
	AppModule		importa	os	módulos		AdminModule		e		PublicoModule	.
	AdminModule		e		PublicoModule		importam	o		SharedModule		e	comunicam-se	com	a	API
HTTP	REST.
Feature-modules
102
https://github.com/jacksongomesbr/angular-escola/tree/livro-modulos-admin-publico-shared
Na	prática,	o		AppModule		funciona	como	um	concentrador	dos	demais	módulos,	já	que	ele
tem	poucas	funcionalidades	específicas,	por	isso	os	demais	módulos,	que	fornecem
funcionalidades,	são	chamados	feature	modules:
	AdminModule		é	responsável	pelas	funcionalidades	administrativas	(requerem	acesso
por	login	e	senha);
	PublicoModule		contém	funcionalidades	que	não	requererem	acesso	por	login	e	senha.
	SharedModule		contém	funcionalidades	que	são	utilizadas	por	outros	módulos.
Na	sequência	o	texto	demonstra	os	elementos	dessa	arquitetura.
Estrutura	do	software
Apresentar	uma	figura	ilustrando	o	diagrama	de	classes	do	software	até	aqui	seria	inútil	por
causa	da	quantidade	de	arquivos	e	artefatos	do	software	até	então.	Entretanto,	para	ter
uma	ideia	do	tamanho	e	da	complexidade	do	software	como	criado	neste	capítulo,	as
tabelas	a	seguir	apresentam	a	relação	de	componentes	em	cada	feature	module	e	uma
breve	descrição	de	cada	um	deles.
Módulo	Admin
Feature-modules
103
Componente Descrição
	AdminComponent	 o	shell	component	do	módulo		Admin	
	CadastroDeDisciplinaComponent	
fornece	um	formulário	para	cadastro	de	uma
disciplina
	CadastroDeTurmaComponent	 fornece	um	formulário	para	cadastro	de	uma	turma
	DisciplinaComponent	
fornece	a	página	inicial	de	uma	disciplina,	com
dados	para	leitura	ou	consulta
	HomeComponent	 fornece	a	página	inicial	do	módulo		Admin	
	ListaDeDisciplinasComponent	
fornece	uma	lista	das	disciplinas	e	dá	acesso	a
outras	funcionalidades:	cadastrar,	excluir	e	editar
	ListaDeTurmasComponent	
fornece	uma	lista	das	turmas	e	dá	acesso	a	outras
funcionalidades:	cadastrar,	excluir	e	editar
	PaginaNaoEncontradaComponent	
fornece	uma	página	para	ser	apresentada	quando
uma	URL	não	combinar	com	alguma	das	rotas	do
módulo		Admin	
	TurmaComponent	
fornece	a	página	inicial	de	uma	turma,	com	dados
para	leitura	ou	consulta
	AdminModule	 o	módulo,	em	si
	AdminRoutingModule	 o	módulo	de	rotas
	Disciplina	 o	model	de	disciplina
	DisciplinasService	
o	serviço	com	a	lógica	de	negócio	para	o
gerenciamento	de	disciplinas
	Turma	 o	model	de	turma
	TurmasService	
o	serviço	com	a	lógica	de	negócio	para	o
gerenciamento	de	turmas
Módulo	Público
Componente Descrição
LoginComponent fornece	um	formulário	para	autenticação	e	acesso	ao	sistema
PublicoComponent o	shell	component	do	módulo		Publico	
PublicoModule o	módulo,	em	si
PublicoRoutingModule o	módulo	de	rotas
Módulo	Shared
Feature-modules
104
Component Descrição
AuthService o	serviço	com	a	lógica	para	autenticação	do	usuário
SharedModule o	módulo,	em	si
Estrutura	de	Navegação
Conforme	o	software	aumenta	na	quantidade	de	componentes	e	funcionalidades	torna-se
interessante	uma	visão	geral	da	navegação	--	até	mesmo	porque	estamos	utilizando	rotas.
A	figura	a	seguir	ilustra	a	navegação	entre	as	telas	(ou	páginas)	do	software.
Figura	3.6.2	-	Estrutura	do	site	na	forma	de	um	mapa	de	navegação
Essa	figura	permite	compreender	que	a	primeira	tela	acessada	é	a	tela	de	login.	A	partir
dela	o	usuário	tem	acesso	à	tela	home	e	às	demais	telas,	como	disciplinas	e	turmas.	A
partir	dessas	telas	outras	podem	ser	acessdas,	como	a	página	da	disciplina	ou	a	página	da
turma.	As	setas	são	bidirecionais	para	indicar	os	caminhos	são	de	ida	e	volta.
Criando	módulos
Para	criar	os	elementos	da	arquitetura	vamos	utilizar	o	Angular	CLI.	Para	começar,	vamos
criar	os	feature	modules.	Para	fazer	isso	execute	a	linha	de	comando	a	seguir.
ng	g	m	Admin	--routing	true
O	comando	cria	o	módulo		Admin	,	na	pasta		src/app/admin	,	e	os	arquivos:
	src/app/admin/admin.module.ts	:	representa	o	módulo	em	si
Feature-modules
105
	src/app/admin/admin-routing.module.ts	:	representa	o	módulo	de	rotas
O	capítulo	anterior	demonstrou	como	trabalhar	com	o	recurso	de	rotas	no	Angular.
Entretanto	o	capítulo	utilizou	o	formato	de	descrever	as	rotas	no	próprio	módulo		AppModule	.
Aqui	neste	capítulo,	como	há	mais	módulos,	cada	módulo	possui,	também,	um	módulo	de
rotas.	Um	módulo	de	rotas	é	um	módulo	que	tem	uma	única	responsabilidade:	definir	as
rotas	do	módulo.	Esse	módulo	será	importado	no	feature	module	para	que	o	Angular
identifique	corretamente	as	rotas	e	os	seus	componentes	associados.	O	comando	anterior
especifica	que	deve	ser	criado	um	módulo	de	rotas	por	meio	da	opção		--routing	true	.
Criando	componentes	nos	módulos
Para	criar	componentes	em	um	módulo	utilizamos	o	Angular	CLI,	usando	a	linha	de
comando	a	seguir:
ng	g	m	Admin/Admin	-m	Admin	--spec	false
O	comando	cria	o	componente		Admin	,	na	pasta		src/app/admin/admin		e	os	arquivos	do
componente.	Usar	o		Admin/Admin		é	uma	forma	de	indicar	para	o	Angular	CLI	que	o
componente		Admin		pertence	ao	módulo		Admin	.	A	opção		-m		é	uma	forma	de	garantir	isso
ainda	mais.	Além	disso	o	comando	também	modifica	o		AdminModule	,	inserindo	o
AdminComponent	no	array		declarations	.
No	padrão	adotado	neste	livro	todo	feature	module	possui	um	componente	de	mesmo
nome	que	é	usado	como	shell	component	--	porque	continuamos	a	usar	o	recurso	de
rotas.
Os	demais	componentes	são	criados	de	forma	semelhante.	Por	exemplo,	a	criação	do
componente	CadastroDeDisciplina:
ng	g	m	Admin/CadastroDeDisciplina	-m	Admin	--spec	false
A	linha	de	comando	cria	o	componente		CadastroDeDisciplina		na	pasta
	src/app/admin/cadastro-de-disciplina		e	modifica	o		AppModule		para	incluir	esse
componente	no	array		declarations	.
Definindo	rotas
Feature-modules
106
Com	a	utilização	de	feature	moduleso	recurso	de	rotas	ganha	uma	utilidade	ainda	mais
marcante	e	evidente.	O	fundamento	adotado	pelo	Angular	é	que	cada	feature	module	pode
possuir	seu	módulo	de	rotas.	Posteriormente,	o	root	module	poderá	importar	o	feature
module	que	desejar.
O	módulo	de	rotas	para	o	módulo		Admin	,	chamado		AdminRouting	,	contém	um	conteúdo
semelhante	ao	seguinte	(omitidas	linhas	com		import	):
...
const	routes:	Routes	=	[
		{
				path:	'admin',	component:	AdminComponent,	children:	[
						{path:	'disciplinas',	component:	ListaDeDisciplinasComponent},
						{path:	'disciplinas/:id',	component:	DisciplinaComponent},
						{path:	'disciplinas/:id/novo',	component:	CadastroDeDisciplinaComponent},
						{path:	'disciplinas/:id/editar',	component:	CadastroDeDisciplinaComponent},
						{path:	'cadastrar-turma',	component:	CadastroDeTurmaComponent},
						{path:	'turmas',	component:	ListaDeTurmasComponent},
						{path:	'turmas/:id',	component:	TurmaComponent},
						{path:	'',	component:	HomeComponent},
						{path:	'**',	component:	PaginaNaoEncontradaComponent}
		]}
];
@NgModule({
		imports:	[RouterModule.forChild(routes)],
		exports:	[RouterModule]
})
export	class	AdminRoutingModule	{
}
Aqui	o	array		routes		ganha	uma	característica	diferenciada:	o	primeiro	elemento,	cujo
atributo		path		tem	valor		'admin'	,	está	relacionado	ao	componente		AdminComponent		e
possui	o	atributo		children	,	que	é	um	array	de	rotas.	O	recurso	que	permite	definir	esses
tipos	de	rotas	é	chamado	de	rotas	filhas.	Assim,	a	rota		'admin'		possui	várias	rotas	filhas.
Além	disso	essa	é	a	forma	de	indicar	para	o	Angular	que	o		AdminComponent		deve	ser	usado
como	shell	component,	ou	seja,	o	Template	dele	contém	o	elemento		router-outlet	.
Note	também	que	há	uma	mudança	na	forma	de	indicar	as	rotas	para	os	metadados	do
módulo:	o	atributo		imports		contém	uma	chamada	para		RouterModule.forChild()	,	que
recebe	como	parâmetro	o	array		routes	.	Esse	é	uma	diferença	marcante	para	a	forma	de
indicar	as	rotas	para	o	root	module,	quando	é	utilizado	o	método		RouterModule.forRoot()	.
Outro	passo	necessário	é	importar	o	módulo	de	rotas	no	feature	module.	A	seguir,	um
trecho	do	AdminModule:
Feature-modules
107
...
@NgModule({
		imports:	[
				CommonModule,
				FormsModule,
				HttpClientModule,
				NgbModule,
				AdminRoutingModule,
				SharedModule
		],
		...
})
export	class	AdminModule	{
}
O	penúltimo	elemento	do	array		imports		é	o	módulo	de	rotas	(	AdminRoutingModule	).
O	módulo	de	rotas	para	o	módulo		Publico	,	chamado		PublicoRouting	,	contém	um
conteúdo	semelhante	ao	seguinte:
...
const	routes:	Routes	=	[
		{
				path:	'',	component:	PublicoComponent,	children:	[
						{path:	'',	component:	LoginComponent}
				]
		}
];
@NgModule({
		imports:	[RouterModule.forChild(routes)],
		exports:	[RouterModule]
})
export	class	PublicoRoutingModule	{
}
O	recurso	de	rotas	filhas	também	é	utilizado	aqui.		PublicoComponent		é	o	shell	component.	O
fato	interessante	é	que	o	atributo		path		contém	o	mesmo	valor		''		nas	duas	rotas.	Como	o
Angular	considera		''		a	rota	padrão,	isso	quer	dizer	que	o		PublicoModule		tem	maior
prioridade	no	momento	em	o	Angular	procurar	encontrar	uma	rota	com	base	na	URL.
Incluindo	as	rotas	dos	feature	modules	no	root
module
Feature-modules
108
O	último	passo	desse	processo	é	importar	os	feature	modules	no	root	module.	A	seguir,
um	trecho	do		AppModule	:
...
@NgModule({
		imports:	[
				BrowserModule,
				NgbModule.forRoot(),
				FormsModule,
				HttpClientModule,
				AdminModule,
				PublicoModule,
				AppRoutingModule
		],
...
})
export	class	AppModule	{
}
Os	módulos		AdminModule	,		PublicoModule		e		AppRoutingModule		são	importados	por	meio	do
atributo		imports		dos	metadados	da	classe		AppModule	.	Como	os	dois	primeiros	importam
seus	respectivos	módulos	de	rotas,	o	root	module	também	tem	conhecimento	delas	e,
assim,	consegue	aplicar	o	mesmo	processo	anterior	de	procura	de	rotas	quando	o	browser
fornece	uma	URL.
Um	aspecto	importante	é	que	a	importação	segue	uma	ordem.	Veja	que,	primeiro,	é
importado	o	módulo		AdminModule	,	depois	o		PublicoModule		e,	por	fim,	o		AppRoutingModule	.
Como	você	viu	no	capítulo	anterior	o	processo	de	procura	de	rotas	percorre	uma	lista	de
rotas	do	início	até	encontrar	uma	rota	correspondente.	Nesse	caso	a	ordem	das
importações	dos	módulos	quer	dizer	para	o	Angular	considerar,	primeiro,	as	rotas	do
	AdminModule	.	Isso	é	muito	importante	porque	as	rotas	do		PublicoModule	,	por	serem	a	rota
padrão,	devem	estar	no	final	do	processo	de	procura	de	rotas.
Shared	modules
O	Angular	utiliza	o	conceito	de	shared	modules	para	indicar	módulos	que	fornecem
recursos	que	são	usados	por	outros.	Conforme	a	arquitetura	do	software	até	o	momento	o
serviço		AuthService		implementa	a	lógica	de	negócio	de	autenticação.	Para	ele	poder	ser
usado	nos	módulos		AdminModule		e		PublicoModule		esse	elemento	do	software	deve	estar
em	um	módulo	compartilhado.	Se	ele	estivesse,	por	exemplo,	no	módulo		PublicoModule		e
o		AdminModule		o	importasse	isso	geraria	problemas	de	ordem	ou	ciclos	de	importação.
Feature-modules
109
Assim,	a	solução	é	isolar	o	AuthService	em	outro	módulo,	no	caso	o	SharedModule.	Na
prática,	um	shared	module	é	também	um	feature	module,	mas,	provavelmente,	ele
apenas	fornecerá	recursos	para	serem	utilizados	em	outros	feature	modules.
Posteriormente,	cada	feature	module	importa	o	shared	module	quando	precisar	utilizar
seus	recursos.
Fluxo	de	trabalho
O	fluxo	de	trabalho	do	capítulo	anterior	acaba	de	ser	atualizado	--	e	também	aumentou	em
complexidade.	Da	mesma	forma	como	antes,	seguir	os	passos	do	processo	também	ajuda
a	compreendê-lo:
1.	 criar	feature	module:	essa	agora	é	a	primeira	coisa	a	fazer;
2.	 criar	componente:	crie	os	componentes	do	feature	module.	Continue	conduzido	esse
processo	de	forma	iterativa,	não	se	preocupe	em	construir	o	componente	por	inteiro,
deixe-o	como	criado	pelo	Angular	CLI;
3.	 definir	rotas:	depois,	defina	as	rotas	no	módulo	de	routas;
4.	 implementar	a	lógica	de	negócio	em	um	serviço:	utilize	serviços	para	implementar	a
lógica	de	negócio;	e
5.	 implementar	lógica	do	componente	e	usar	o	serviço:	volte	a	trabalhar	com	cada
compomente.
Feature-modules
110
	Introdução
	Iniciando com o Angular
	Angular CLI
	Software de gerenciamento escolar
	Criando o projeto
	Depurando código no browser
	Iniciando com teste de software
	Apresentando a lista de disciplinas
	Cadastrando uma disciplina
	Excluindo uma disciplina
	Editando dados de uma disciplina
	Interação entre componentes
	Serviços
	Acessando dados externos de forma assíncrona
	Acessando dados de uma API HTTP
	Rotas
	Feature-modules

Mais conteúdos dessa disciplina