ASP.NET Core – Highcharts com Angular 5

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

Figura 1 – Tela de votação

Figura 2 – Resultado da votação

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)

Figura 3 – Projeto Angular

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.

Figura 4 – obtercandidatos

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

Figura 5 – 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

Figura 7 - resultado.component.html

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).

Figura 6 - nav-menu

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