Angular 2 - Resolvido

Último exemplo, https://material.angular.io/components/table/examples. Mas mudei para buscar da base de dados. As informações vem do banco de dados.

Sempre dá este erro:

EstadoComponent_Host.ngfactory.js? [sm]:1 ERROR TypeError: Cannot set property 'paginator' of undefined
    at EstadoComponent.ngAfterViewInit (estado.component.ts:44)
    at callProviderLifecycles (core.js:12706)
    at callElementProvidersLifecycles (core.js:12673)
    at callLifecycleHooksChildrenFirst (core.js:12656)
    at checkAndUpdateView (core.js:13811)
    at callViewAction (core.js:14153)
    at execEmbeddedViewsAction (core.js:14111)
    at checkAndUpdateView (core.js:13803)
    at callViewAction (core.js:14153)
    at execComponentViewsAction (core.js:14085)

Meu código

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

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

import {MatPaginator, MatSort, MatTableDataSource} from '@angular/material';
import { Estado } from '../model/estado.model';
import { EstadoService } from './estado.service';

@Component({
  selector: 'app-estado',
  templateUrl: './estado.component.html',
  styleUrls: ['./estado.component.css']
})
  export class EstadoComponent implements OnInit {
    //displayedColumns = ['id', 'name', 'progress', 'color'];
    displayedColumns = ['pais', 'descricao', 'sigla'];
    dataSource: MatTableDataSource<Estado>;
    
    //dataSource: MatTableDataSource<UserData>;
  
    @ViewChild(MatPaginator) paginator: MatPaginator;
    @ViewChild(MatSort) sort: MatSort;
      
    estados: Estado[];

    constructor(private router: Router, private estadoService : EstadoService) { }

    ngOnInit() {
     
      this.estadoService.todos().forEach(
      //subscribe( 
        (data :any) => { 
          this.estados = data.lista;
          this.dataSource = new MatTableDataSource(this.estados);
      });
    }
  
    /**
     * Set the paginator and sort after the view init since this component will
     * be able to query its view for the initialized paginator and sort.
     */
    ngAfterViewInit() {
      this.dataSource.paginator = this.paginator;
      this.dataSource.sort = this.sort;
    }
  
    applyFilter(filterValue: string) {
      filterValue = filterValue.trim(); // Remove whitespace
      filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
      this.dataSource.filter = filterValue;
    }
  }
  
  /** Builds and returns a new User. */
  function createNewUser(id: number): UserData {
    const name =
        NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
        NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';
  
    return {
      id: id.toString(),
      name: name,
      progress: Math.round(Math.random() * 100).toString(),
      color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
    };
  }
  
  /** Constants used to fill up our data base. */
  const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
    'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
  const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
    'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
    'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];
  
  export interface UserData {
    id: string;
    name: string;
    progress: string;
    color: string;
  }

  function buscarEstado() {
    var i : number;
    i = 0;
    this.estadoService.todos().subscribe( 
      (data :any) => { 
        this.estados = data.lista;
    });

  }

Onde você criou/instanciou o atributo dataSource?

Entendo que aqui dataSource: MatTableDataSource;

Isto é a declaração, você não instanciou este objeto, logo, o mesmo está nulo. Não existe, em nenhum lugar, o

new MatTableDataSource();

antes da linha em que o erro é disparado. Entendeu?

Não sei se vou conseguir te explicar.

Peguei o exemplo do site.

No exemplo a grade é populada por um array que é construído no momento da execução. No construtor, tem o for que monta o conteúdo para a tabela for (let i = 1; i <= 100; i++) { users.push(createNewUser(i)); }

No meu caso ele vai no banco de dados, o que faz correto, faz a consulta no Servidor JAVA, retorna as informações, monta a tabela, mas não tem paginação.

Não pesquisa e nem altera a quantidade de páginas, conforme imagem

Pois quando ele entra nestes métodos/funções, this.dataSource é nulo ou vazio.

ngAfterViewInit() {
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;
      }

      applyFilter(filterValue: string) {
        filterValue = filterValue.trim(); // Remove whitespace
        filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
        this.dataSource.filter = filterValue;
      }

No construtor aonde ele faz requisição ao servidor, ele deveria espera o retorno, para depois renderizar a tela e preencher as variáveis.

Conseguiu entender ?

Segue o exemplo do site

import {Component, ViewChild} from '@angular/core';
import {MatPaginator, MatSort, MatTableDataSource} from '@angular/material';

/**
 * @title Data table with sorting, pagination, and filtering.
 */
@Component({
  selector: 'table-overview-example',
  styleUrls: ['table-overview-example.css'],
  templateUrl: 'table-overview-example.html',
})
export class TableOverviewExample {
  displayedColumns = ['id', 'name', 'progress', 'color'];
  dataSource: MatTableDataSource<UserData>;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor() {
    // Create 100 users
    const users: UserData[] = [];
    for (let i = 1; i <= 100; i++) { users.push(createNewUser(i)); }

    // Assign the data to the data source for the table to render
    this.dataSource = new MatTableDataSource(users);
  }

  /**
   * Set the paginator and sort after the view init since this component will
   * be able to query its view for the initialized paginator and sort.
   */
  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

  applyFilter(filterValue: string) {
    filterValue = filterValue.trim(); // Remove whitespace
    filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
    this.dataSource.filter = filterValue;
  }
}

/** Builds and returns a new User. */
function createNewUser(id: number): UserData {
  const name =
      NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
      NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';

  return {
    id: id.toString(),
    name: name,
    progress: Math.round(Math.random() * 100).toString(),
    color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
  };
}

/** Constants used to fill up our data base. */
const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
  'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
  'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
  'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];

export interface UserData {
  id: string;
  name: string;
  progress: string;
  color: string;
}

Sim, eu entendi.
Você que não entendeu que você nunca instanciou o dataSource.

ngAfterViewInit() {
    this.dataSouce = new MatTableDataSource();//Esta linha que falta
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
}

Entendi, mas é porque no exemplo do site não está assim…

Alterado o erro continua e deu outro erro:

ERROR in src/app/estado/estado.component.ts(46,12): error TS2551: Property ‘dataSouce’ does not exist on type ‘EstadoComponent’. Did you mean ‘dataSource’?

Segue imagens

this.dataSouce = new MatTableDataSource();
dataSouce está escrito incorretamente. Tente colocar this.dataSource.

Não, o erro diz que você esqueceu de escrever o nome corretamente. Você escreveu

 this.dataSouce

Quando deveria escrever

 this.dataSource

Sim, estou cego kkkk.

Mas de qualquer maneira não funciona e o erro continua.

Cara, o mesmo erro? Tem certeza?

Percebi que tinha colocado esta instrução this.dataSouce = new MatTableDataSource();//Esta linha que falta, no local errado.

Na verdade não tem erro no console, mas ele não tem o resultado.
Quando entro na página, ele ainda não carregou a informação no banco de dados e por isto não tem resultado neste momento, conforme imagem.

Fora ter instanciado em local errado, você chegou a debugar para ver se os dados estão sendo retornados pelo serviço?

Como disse, na inicialização deste componente do angular, os dados ainda não foram buscados do banco de dados, conforme imagem anterior.

Primeiro ele carrega o componente MatTableDataSource no metodo ngAfterViewInit(). depois ele consulta a base de dados no método ngOnInit. Deveria ser ao contrário.

Tem certeza? Cara, after é depois…

Tenho certeza, quando ele chega nesta linha, está vazio, conforme imagem.

Inclusive this.dataSource.sort = this.sort;, aqui o this.sorte está undefined

Que está vazio eu não duvido, o que eu não tenho certeza é que a ordem de acontecimentos é afterView ou oninit.

Entrei na tela. Tem dois breackpoints conforme imagem.

Os breackpoints estão nas linhas 32 e 37.

primeiro ele para na linha 37, aonde está o método ngAfterViewInit, e depois ele vai para a linha 37, aonde faz a consulta com o banco de dados no método ngOnInit.

Entendeu ?

Certo, e por que ele não trouxe os dados necessários?

Porque na primeira vez que ele para no breakpoint ele não foi ao banco de dados ainda.

Somente na 2ª vez. Ai a variável this.dataSource está vazia

Acho que vc não entendeu.