Neste artigo vamos criar uma aplicação utilizando ASP.NET Core WebAPi, Angular 5 e Highcharts. Como estamos na semana das eleições nossa aplicação terá duas telas, uma onde o usuário poderá votar nos presidenciáveis e outra com o resultado das votações. A ideia deste artigo é que o leitor aprenda (aprendadotnet) Web API, Entity Framework e Angular 6.
Ferramentas necessárias para criar o projeto.
- Visual Studio 2017 e
- SQL Server
- .NET Core – https://www.microsoft.com/net/download
- Node.js
- Angular Cli – https://cli.angular.io/
Abaixo as telas do projeto (Figura 1) tela de votação, (Figura 2) resultados.
Link do projeto, aproveite e vote.
https://goo.gl/Phs9eu


Nosso primeiro passo será criar o a tabela de candidatos em seguida vamos incluir os presidenciáveis com seus respectivos números e partidos.
CREATE TABLE Candidatos2018 ( CandidatoId INTEGER IDENTITY(1,1) PRIMARY KEY, CandidatoNome NVARCHAR(80) NOT NULL, QuantidadeVotos INTEGER NOT NULL ) INSERT INTO Candidatos2018 VALUES ('ALVARO DIAS - PODE - 19',0) INSERT INTO Candidatos2018 VALUES ('CABO DACIOLO - PATRI - 51',0) INSERT INTO Candidatos2018 VALUES ('CIROS GOMES - PDT - 12',0) INSERT INTO Candidatos2018 VALUES ('EYMAEL - DC - 27',0) INSERT INTO Candidatos2018 VALUES ('FERNANDO HADDAD - PT - 13',0) INSERT INTO Candidatos2018 VALUES ('GERALDO ALCKIMIN - PSDB - 45',0) INSERT INTO Candidatos2018 VALUES ('GUILHERME BOULOS - PSOL - 50',0) INSERT INTO Candidatos2018 VALUES ('HENRIQUE MEIRELLES - MDB - 15',0) INSERT INTO Candidatos2018 VALUES ('JAIR BOLSONARO - PSL - 17',0) INSERT INTO Candidatos2018 VALUES ('JOÃO AMOÊDO - NOVO - 30',0) INSERT INTO Candidatos2018 VALUES ('JOÃO GOULART FILHO - PPL - 54',0) INSERT INTO Candidatos2018 VALUES ('MARINA SILVA - REDE - 18',0) INSERT INTO Candidatos2018 VALUES ('VERA - PSTU - 16',0)
Criação do projeto
Crie um projeto Web ASP.NET Core Web Application, informe em Name EleicoesPresidente e na Solution name Eleicoes2018.
Em seguida selecione nos templantes Angular e desmarque Configure for HTTPS e clique em OK. (Figura 3)

Instalação dos pacotes Highcharts
Abra o arquivo package.json que encontra-se na pasta ClientApp e adicione conforme as linhas 32, 33 e 42 os pacotes abaixo, perceba que assim que você salvar o arquivo o Visual Studio irá realizar o download dos pacotes e salvar na pasta node_modules.
“angular-highcharts”: “^5.2.12”,
“highcharts”: “^6.1.0”
“@types/highcharts”: “^5.0.22”,
{ "name": "EleicoesPresidentes", "version": "0.0.0", "license": "MIT", "scripts": { "ng": "ng", "start": "ng serve --extract-css", "build": "ng build --extract-css", "build:ssr": "npm run build -- --app=ssr --output-hashing=media", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "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/platform-server": "^5.2.0", "@angular/router": "^5.2.0", "@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.5", "aspnet-prerendering": "^3.0.1", "bootstrap": "^3.3.7", "core-js": "^2.4.1", "rxjs": "^5.5.6", "zone.js": "^0.8.19", "angular-highcharts": "^5.2.12", "highcharts": "^6.1.0", }, "devDependencies": { "@angular/cli": "~1.7.0", "@angular/compiler-cli": "^5.2.0", "@angular/language-service": "^5.2.0", "@types/jasmine": "~2.8.3", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", "@types/highcharts": "^5.0.22", "codelyzer": "^4.0.1", "jasmine-core": "~2.8.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~2.0.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.1.2", "ts-node": "~4.1.0", "tslint": "~5.9.1", "typescript": "~2.5.3" }, "optionalDependencies": { "node-sass": "^4.9.0" } }
Instalação dos pacotes Entity Framework Core
Continuando a configuração do projeto nosso próximo passo será instalar os pacotes do Entity Framework Core, abra o Package Manager Console e digite os comando abaixo.
Acesso ao PMC – Tools >> NuGet Package Manager >> Package Manager Console.
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
Scaffold para a criação do DbContext
Como criamos a tabela no início do artigo vamos gerar a classe Candidato2018 e o DbContext através do Scaffold abaixo. Execute o comando no Package Manager Console, informe os dados do seu banco, o teste para saber se tudo ocorreu Ok, será a criação das classes na pasta Models, caso queira criar as classes ao invés de utilizar o Scaffold segue abaixo após o Scaffold as classes C#.
Scaffold-DbContext “Data Source=(localdb)\mssqllocaldb;Initial Catalog=AprendaDotNet;Integrated Security=False;User Id=sa;Password=xxxxSenha;MultipleActiveResultSets=True” Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Candidatos2018
DbContext
using Microsoft.EntityFrameworkCore; namespace EleicoesPresidentes.Models { public partial class AprendaDotNetContext : DbContext { public AprendaDotNetContext() { } public AprendaDotNetContext(DbContextOptions<AprendaDotNetContext> options) : base(options) { } public virtual DbSet<Candidatos2018> Candidatos2018 { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Candidatos2018>(entity => { entity.HasKey(e => e.CandidatoId); entity.Property(e => e.CandidatoNome) .IsRequired() .HasMaxLength(80); }); } } }
Classe Candidatos2018
namespace EleicoesPresidentes.Models { public partial class Candidatos2018 { public int CandidatoId { get; set; } public string CandidatoNome { get; set; } public int QuantidadeVotos { get; set; } } }
Se você utilizou o Scaffold perceba que a string de conexão foi criada no DbContext, vamos evitar esta configuração, para isso remova o método.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
Startup.cs – Configuração da String de Conexão
Como removemos a string de conexão do DbContext vamos incluir na classe Startup.cs, abaixo como ficará o método ConfigureServices, e no próximo bloco incluímos a string de conexão no arquivo appsettings.json.
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddDbContext<AprendaDotNetContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); }
{ "ConnectionStrings": { "DefaultConnection": "Data Source=(localdb)\\mssqllocaldb;Initial Catalog=AprendaDotNet;Integrated Security=False;User Id=sa;Password=xxxSuaSenha;MultipleActiveResultSets=True" }, "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*" }
Interfaces do projeto
Após as configurações vamos enfim começar a codificar nossa aplicação, vamos iniciar pelas Interfaces do projeto, crie uma pasta chama Interface e crie a Interface IEleicoesRepositorio.cs e digite ou copie o código abaixo.
Os métodos que iremos criar serão obter todos os candidatos, um outro quer irá registar o voto e um que irá buscar o número de total de votos
using System.Collections.Generic; using System.Threading.Tasks; using EleicoesPresidentes.Models; namespace EleicoesPresidentes.Interfaces { public interface IEleicoesRepositorio { Task<IEnumerable<Candidatos2018>> ObterCandidatos(); Task<int> RegistarVoto(Candidatos2018 candidato); Task<int> ObterTotalVotos(); } }
Repositório
Após a criação da Interface vamos criar o repositório e a classe que irá herdar da Interface.
Crie um pasta chamada Repositorio e nesta pasta crie uma classe de nome EleicoesRepositorio.cs, e codifique conforme código abaixo.
Perceba que a classe herda de IEleicoesRepositorio e a criação do construtor que inicializa o DbContext para que possamos ter acesso ao modelo da aplicação.
Em seguida implementamos os três métodos necessários, o ObterCandidatos retorna todos os registros, o RegistrarVoto que grava o voto e o total de votos.
Perceba que todos os métodos são assíncronos.
using System.Collections.Generic; using System.Threading.Tasks; using EleicoesPresidentes.Interfaces; using EleicoesPresidentes.Models; using Microsoft.EntityFrameworkCore; namespace EleicoesPresidentes.Repositorio { public class EleicoesRepositorio : IEleicoesRepositorio { private readonly AprendaDotNetContext _context; public EleicoesRepositorio(AprendaDotNetContext context) { _context = context; } public async Task<IEnumerable<Candidatos2018>> ObterCandidatos() { return await _context.Candidatos2018.ToListAsync(); } public async Task<int> RegistarVoto(Candidatos2018 candidato) { return await _context.Database.ExecuteSqlCommandAsync( "update Candidatos2018 set QuantidadeVotos = QuantidadeVotos + 1 where CandidatoId = {0}", parameters: candidato.CandidatoId); } public async Task<int> ObterTotalVotos() { return await _context.Candidatos2018.SumAsync(t => t.QuantidadeVotos); } } }
IEleicoesServico
Na pasta Interfaces crie uma interface chamada IEleicoesServico.cs e codifique conforme código abaixo.
using System.Threading.Tasks; using EleicoesPresidentes.Models; using Microsoft.AspNetCore.Mvc; namespace EleicoesPresidentes.Interfaces { public interface IEleicosServico { Task<IActionResult> ObterCandidatos(); Task<IActionResult> RegistarVoto([FromBody] Candidatos2018 candidato); Task<IActionResult> ObterTotalVotos(); } }
Servicos / EleicoesServico.cs
Em seguida vamos criar uma pasta chamada Servicos e a classe EleicoesServico.cs, esta classe irá herdar de IEleicosServico, ela que irá realizar a consulta as chamadas no repositório, perceba que no construtor chamamos a Interface do repositório e nos métodos retornamos os verbos corretos com por exemplo OkObjectResult no momento que retornamos os candidatos.
O que acho interessante nesta abordagem é que a Controller não fica responsável por retornar os verbos, a responsabilidade fica por conta do Servico.
using System.Threading.Tasks; using EleicoesPresidentes.Interfaces; using EleicoesPresidentes.Models; using Microsoft.AspNetCore.Mvc; namespace EleicoesPresidentes.Servicos { public class EleicoesServico : IEleicosServico { private readonly IEleicoesRepositorio _repositorio; public EleicoesServico(IEleicoesRepositorio repositorio) { _repositorio = repositorio; } public async Task<IActionResult> ObterCandidatos() { var candidatos = await _repositorio.ObterCandidatos(); return new OkObjectResult(candidatos); } public async Task<IActionResult> RegistarVoto(Candidatos2018 candidato) { if (candidato == null) return new BadRequestResult(); var row = await _repositorio.RegistarVoto(candidato); if (row > 0) return new OkObjectResult(row); return new StatusCodeResult(500); } public async Task<IActionResult> ObterTotalVotos() { var votos = await _repositorio.ObterTotalVotos(); if (votos > 0) return new OkObjectResult(votos); return new StatusCodeResult(500); } } } }
EleicoesController
Nosso próximo passo será criar a Controller, clique com o botão direito do mouse na pasta Controller em seguida Add >> Controller e selecione API Controller – Empty e digite o código abaixo.
A Controller faz a chamada os métodos do serviço, perceba os verbos nas Actions, como por exemplo o Put no momento de registrar o voto e a rota de cada Action.
using System.Threading.Tasks; using EleicoesPresidentes.Interfaces; using EleicoesPresidentes.Models; using Microsoft.AspNetCore.Mvc; namespace EleicoesPresidentes.Controllers { [Route("api/[controller]")] [ApiController] public class EleicoesController : ControllerBase { private readonly IEleicosServico _eleicosServico; public EleicoesController(IEleicosServico eleicosServico) { _eleicosServico = eleicosServico; } [HttpGet] [Route("ObterCandidatos")] public async Task<IActionResult> ObterCandidatos() { return await _eleicosServico.ObterCandidatos(); } [HttpPut] [Route("RegistrarVoto")] public async Task<IActionResult> RegistarVoto(Candidatos2018 candidato) { return await _eleicosServico.RegistarVoto(candidato); } [HttpGet] [Route("TotalVotos")] public async Task<IActionResult> ObterTotalVotos() { return await _eleicosServico.ObterTotalVotos(); } } }
Injeção de dependência
Precisamos configurar a classe Startup.cs e incluir em ConfigureServices as chamadas para as Interfaces e suas implementações, perceba que para o repositório utilizamos AddScoped para o serviço AddTransient, pois os serviços são sem estado.
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddDbContext<AprendaDotNetContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); //Objetos transitórios são sempre diferentes; uma nova instância é fornecida para todos os controladores e todos os serviços. //Objetos com escopo são os mesmos em uma solicitação, mas diferentes entre solicitações diferentes //Objetos singleton são os mesmos para cada objeto e cada solicitação(independentemente de uma instância ser fornecida ConfigureServices) services.AddScoped<IEleicoesRepositorio, EleicoesRepositorio>(); services.AddTransient<IEleicosServico, EleicoesServico>(); // In production, the Angular files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); }
Teste da aplicação
Abra o arquivo launchSettings.json que encontra-se em Properties e altere a propriedade sslPort para 0 em seguida execute a aplicação. Vamo testar através do navegar a chamada da Action ObterCandidatos.
http://localhost:51871/api/eleicoes/obtercandidatos
A porta acima pode mudar na sua aplicação, confirme em
launchSettings qual será a sua.
Conforme (Figura 4) obtemos todos os candidatos.

Angular 5
Até agora trabalhamos com a criação do Back de nossa aplicação, em seguida vamos trabalhar com o Front e vamos criar as páginas de votação e resultados.
Angular Cli
Vamos através do Angular Cli criar um serviço angular e dois componentes, execute os comandos abaixo, lembre-se que você tem que ter instalado o Node.js e Angular cli.
Criacão do Serviço na pasta services
ng g s services/eleicoeseleicosservices
Criação do componente votacao
ng g c votacao
Criação do componente resultado
ng g c resultado
Candidato Model
Em seguida vamos criar uma pasta chamada Model e criar um arquivo typescript e a classe Candidato e codifique conforme abaixo.
export class Candidato { candidatoId: number; candidatoNome: string; quantidadeVotos: number; quantidadeTotal: number; }
EleicoesService
No código abaixo temos as chamadas para as Actions da API e a criação dos respectivos métodos.
import { Injectable, Inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; import { Candidato } from '../model/candidato.model'; @Injectable() export class EleicoesService { baseUrl: string; constructor(private _http: HttpClient, @Inject('BASE_URL') baseUrl: string) { this.baseUrl = baseUrl; } public obterCandidatos() { return this._http.get<Candidato[]>(this.baseUrl + 'api/Eleicoes/ObterCandidatos'); } obterTotalVotos() { return this._http.get(this.baseUrl + 'api/Eleicoes/TotalVotos'); } registrarVoto(candidato: Candidato) { return this._http.put(this.baseUrl + 'api/Eleicoes/RegistrarVoto', candidato); } }
O resultado final da estrutura do nosso projeto deve ficar igual a (Figura 5), temos candidatomodel.ts na pasta model, os componentes resultado e votacao e eleicoes.service.ts
Estrutura do projeto

Nossos próximos passos serão codificar os componentes votacao e resultado, vamos iniciar pelo votacao.component.ts.
votacao.component.ts
Em votacao.component estamos chamando da service os três métodos que foram criado na API, perceba que o obterCandidatos
import { Component, OnInit } from '@angular/core'; import {Candidato} from '../model/candidato.model'; import {Router} from '@angular/router'; import {EleicoesService} from '../services/eleicoes.service'; @Component({ selector: 'app-votacao', templateUrl: './votacao.component.html', styleUrls: ['./votacao.component.css'] }) export class VotacaoComponent implements OnInit { candidatos: Candidato[]; constructor(private candidatoService: EleicoesService, private _router: Router) {} ngOnInit() { this.candidatoService.obterCandidatos() .subscribe((data: Candidato[]) => { this.candidatos = data; }); } registrarVoto(candidato: Candidato): void { this.candidatoService.registrarVoto(candidato) .subscribe((data) => { this._router.navigate(['/resultado']); }); } }
votacao.component.html
No componente abaixo criamos um tabela e através do ngFor listamos todos os candidatos, e um botão Votar para cada um deles.
<h1>Eleiçoes 2018</h1> <h3>Escolha o novo Presidente do Brasil !!! </h3> <hr /> <p *ngIf="!candidatos"><em>Loading...</em></p> <table class='table' *ngIf="candidatos"> <thead> <tr> <th>Candidatos</th> </tr> </thead> <tbody> <tr *ngFor="let candidato of candidatos"> <td>{{ candidato.candidatoNome }}</td> <td> <button (click)="registrarVoto(candidato)" class="btn btn-primary"> Votar <i class="glyphicon glyphicon-thumbs-up"></i></button> </td> </tr> </tbody> </table> <!-- /wp:shortcode --> <!-- wp:heading {"level":4} --> <h4>resultado.component.ts</h4> <!-- /wp:heading --> <!-- wp:paragraph --> <p>Resultado componente obtemos todos os candidatos e total e votos, utilizando Observable.zip guardo nas variáveis totalVotos e candidatosList o resultado para enfim criar os gráficos.<br/><br/>O método createCharts () criará o gráfico de colunas com a ajuda da biblioteca Highcharts. A quandidade de votos é selecionada como eixo Y e o nome do candidato é selecionado como eixo X. <br/></p> <!-- /wp:paragraph --> <!-- wp:shortcode --> import { Component, OnInit } from '@angular/core'; import {Candidato} from '../model/candidato.model'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/zip'; import {EleicoesService} from '../services/eleicoes.service'; import {Chart} from 'angular-highcharts'; @Component({ selector: 'app-resultado', templateUrl: './resultado.component.html', styleUrls: ['./resultado.component.css'] }) export class ResultadoComponent implements OnInit { public chart: any; public totalVotos: any; public candidatosList: Candidato[]; constructor(private _candidatoService: EleicoesService) {} ngOnInit() { Observable.zip(this._candidatoService.obterTotalVotos(), this._candidatoService.obterCandidatos()) .subscribe(([totalVotos, candidatosListaDados]) => { this.totalVotos = totalVotos; this.candidatosList = candidatosListaDados; this.createCharts(); }); } createCharts() { this.chart = new Chart({ chart: { type: 'line' }, title: { text: 'Eleições 2018' }, xAxis: { type: 'category', labels: { rotation: -45, style: { fontSize: '10px', fontFamily: 'Verdana, sans-serif' } } }, yAxis: { min: 0, title: { text: 'Porcentagem de votos' } }, legend: { enabled: false }, tooltip: { pointFormat: 'Número de Votos: <b>{point.y}</b>' }, series: [{ type: 'column', data: [ { name: this.candidatosList[0].candidatoNome, y: this.candidatosList[0].quantidadeVotos, color: 'rgba(253, 185, 19, 0.85)' }, { name: this.candidatosList[1].candidatoNome, y: this.candidatosList[1].quantidadeVotos, color: 'rgba(0, 76, 147, 0.85)' }, { name: this.candidatosList[2].candidatoNome, y: this.candidatosList[2].quantidadeVotos, color: 'rgba(170, 69, 69, 0.85)' }, { name: this.candidatosList[3].candidatoNome, y: this.candidatosList[3].quantidadeVotos, color: 'rgba(112, 69, 143, 0.85)' }, { name: this.candidatosList[4].candidatoNome, y: this.candidatosList[4].quantidadeVotos, color: 'rgba(0, 93, 160, 0.85)' }, { name: this.candidatosList[5].candidatoNome, y: this.candidatosList[5].quantidadeVotos, color: 'rgba(45, 77, 157, 0.85)' }, { name: this.candidatosList[6].candidatoNome, y: this.candidatosList[6].quantidadeVotos, color: 'rgba(0, 0, 0, 0.85)' }, { name: this.candidatosList[7].candidatoNome, y: this.candidatosList[7].quantidadeVotos, color: 'rgba(251, 100, 62, 0.85)' }, { name: this.candidatosList[8].candidatoNome, y: this.candidatosList[8].quantidadeVotos, color: 'rgba(118, 32, 44, 0.85)' }, { name: this.candidatosList[9].candidatoNome, y: this.candidatosList[9].quantidadeVotos, color: 'rgba(28, 640, 0, 0.85)' }, { name: this.candidatosList[10].candidatoNome, y: this.candidatosList[10].quantidadeVotos, color: 'rgba(86, 38, 28, 0.85)' }, { name: this.candidatosList[11].candidatoNome, y: this.candidatosList[11].quantidadeVotos, color: 'rgba(51, 105, 16, 0.85)' }, { name: this.candidatosList[12].candidatoNome, y: this.candidatosList[12].quantidadeVotos, color: 'rgba(44, 77, 105, 0.85)' } ], }] }); } }
resultado.component.html
No resultado component vamos adicionar a div chart e o total de votos, caso ocorra um erro na div confirme se você importou ChartModule em app.module.ts
import {ChartModule} from 'angular-highcharts';
ChartModule

app.module.ts
Em app.module.ts incluímos em providers: [EleicoesService] e nas rotas.
{ path: 'votacao', component: VotacaoComponent },
{ path: 'resultado', component: ResultadoComponent },
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; import { NavMenuComponent } from './nav-menu/nav-menu.component'; import { HomeComponent } from './home/home.component'; import { CounterComponent } from './counter/counter.component'; import { FetchDataComponent } from './fetch-data/fetch-data.component'; import { VotacaoComponent } from './votacao/votacao.component'; import { ResultadoComponent } from './resultado/resultado.component'; import {EleicoesService} from './services/eleicoes.service'; import {ChartModule} from 'angular-highcharts'; @NgModule({ declarations: [ AppComponent, NavMenuComponent, HomeComponent, CounterComponent, FetchDataComponent, VotacaoComponent, ResultadoComponent ], imports: [ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), HttpClientModule, FormsModule, ChartModule, RouterModule.forRoot([ { path: '', component: HomeComponent, pathMatch: 'full' }, { path: 'counter', component: CounterComponent }, { path: 'votacao', component: VotacaoComponent }, { path: 'resultado', component: ResultadoComponent }, { path: 'fetch-data', component: FetchDataComponent }, ]) ], providers: [EleicoesService], bootstrap: [AppComponent] }) export class AppModule { }
nav-menu.component.html
Para finalizar o projeto, vamos adicionar em nav-menu o link para a votação. (Figura 6).

O código fonte do projeto está disponível no GitHub através do link abaixo. Fontes: https://github.com/fabiogalante/core_chart_eleicoes2018
Dúvidas e sugestões
fabiogalantemans@aprendadotnet.com.br