Solucionado (ver solução)
Solucionado
(ver solução)
17
respostas

metodo get retornando undefined

Olá, estou tentando criar uma aplicação para listar o histórico dos contratos da BVMF, porém agregando mais informações, para isso criei alguns métodos getter numa classe específica que deveriam retornar esses dados que preciso, porém não retornam nenhum valor, pois o retorno aparece como undefined ao logar no console. O Angular está conseguindo instanciar a classe e preencher os atributos a partir do JSON, mas aparentemente os métodos getter não estão funcionando, pois faço uma chamada de teste logo após o Service me devolver os dados e como disse obtenho undefined no console. Coloquei alguns logs para ver a chamada do método, mas nada aparece no console, indicando talvez que esse método não esteja sendo chamado.

Por favor podem me ajudar a encontrar o problema com meu código? Segue abaixo:

//arquivo: consulta.component.ts

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

import { ContratoService } from '../contrato/contrato.service';
import { Mercadoria} from '../mercadoria/mercadoria';
import { MercadoriaService} from '../mercadoria/mercadoria.service';
import { Contrato } from '../contrato/contrato';
import {FormGroup,FormBuilder,Validators } from '@angular/forms';
import {Movimento} from './movimento'


@Component({
    moduleId:module.id,
    selector:'consulta',
    templateUrl:'./consulta.component.html',
    providers:[ContratoService,Movimento,MercadoriaService]
})
export class ConsultaComponent implements OnInit{

    codigo:string;
    data:string;
    mercadoria: Mercadoria;
    historico: Movimento[];
    mercadorias: Mercadoria[];
    mensagem:string='';

    constructor(private contratoService:ContratoService,private mercadoriaService:MercadoriaService){

    }

    ngOnInit(): void {
        this.mercadorias = this.mercadoriaService.getMercadorias();
        this.mercadoria = new Mercadoria();
        this.historico=[];
    }


    pesquisar(event){
        event.preventDefault();
        let mercadoria =this.getMercadoriaByCode(this.codigo.substr(0,3)); 
        this.mercadoria=mercadoria;
        console.log(this.mercadoria);
        this.contratoService.buscaContrato(this.codigo)
        .subscribe(historico=>{
            console.log('contrato localizado...');
            this.historico=historico;
            this.historico.forEach(v=>{
                console.log(JSON.stringify(v));
                console.log(v.frequencia);
                console.log(v.grafico);
                console.log(v.alvo);
            });
        }, erro => console.log(erro))

    }
    private getMercadoriaByCode(code):any {
        return this.mercadorias.filter(data => data.codigo == code)
    }

}
//arquivo: movimento.ts
import {Injectable} from '@angular/core';
@Injectable()
export class Movimento{

    data:string;
    fechamento: number;
    variacao: number;
    variacao_pct: string;
    minima: number;
    maxima: number;
    volume: number;

    constructor(){
        console.log('constructor called');
    }

    public get frequencia(){
        console.log('called frequencia...');
        let variacao = this.maxima - this.minima
        let frequencia = variacao * 0.10

        return frequencia;
    }

    public get alvo(){
        console.log('called alvo...');
        return this.frequencia / 2
    }

    public get grafico(){
        console.log('called grafico...');
        return this.frequencia * 2
    }
}
//arquivo mercadoria.data.ts

import {Mercadoria} from './mercadoria';

export const MERCADORIAS: Mercadoria[]=[
    {codigo:"AUD", mercadoria:"Dólar comercial australiano "},
    {codigo:"BGI", mercadoria:"Boi gordo "},
    {codigo:"BRI", mercadoria:"IBrX-50 "},
    {codigo:"CAD", mercadoria:"Dólar comercial canadense "},
    {codigo:"CCM", mercadoria:"Milho "},
    {codigo:"CHF", mercadoria:"FRANCO SUÍÇO "},
    {codigo:"CLP", mercadoria:"PESO CHILENO "},
    {codigo:"DAP", mercadoria:"Cupom de DI x IPCA "},
    {codigo:"DDI", mercadoria:"Cupom cambial "},
    {codigo:"DI1", mercadoria:"DI de 1 dia "},
    {codigo:"DOL", mercadoria:"Dólar comercial "},
    {codigo:"ETH", mercadoria:"Etanol Hidratado "},
    {codigo:"EUR", mercadoria:"Euro "},
    {codigo:"FRC", mercadoria:"FRA de cupom "},
    {codigo:"GBP", mercadoria:"Libra Esterlina "},
    {codigo:"IAP", mercadoria:"IPCA "},
    {codigo:"ICF", mercadoria:"Café Arábica 4/5 "},
    {codigo:"IGM", mercadoria:"IGP-M "},
    {codigo:"IND", mercadoria:"Ibovespa "},
    {codigo:"ISP", mercadoria:"S&P 500 "},
    {codigo:"JPY", mercadoria:"Iene "},
    {codigo:"MXN", mercadoria:"Peso mexicano "},
    {codigo:"NZD", mercadoria:"DÓLAR DA NOVA ZELÂNDIA "},
    {codigo:"OC1", mercadoria:"Contrato Futuro de OC1 "},
    {codigo:"OZ1", mercadoria:"Ouro 250g "},
    {codigo:"SJC", mercadoria:"Soja Financeira Cross Listing "},
    {codigo:"T10", mercadoria:"US T-Note 10 anos "},
    {codigo:"TRY", mercadoria:"LIRA TURCA "},
    {codigo:"WDO", mercadoria:"Dólar Comercial Míni "},
    {codigo:"WIN", mercadoria:"Ibovespa Mini "},
    {codigo:"WTI", mercadoria:"Petróleo Mini "},
    {codigo:"ZAR", mercadoria:"RANDE DA ÁFRICA DO SUL "},
]
//arquivo mercadoria.service.ts
import { Injectable } from '@angular/core';

import {Mercadoria} from './mercadoria';
import {MERCADORIAS} from './mercadoria.data';


@Injectable()
export class MercadoriaService {
    getMercadorias(): Mercadoria[]{
        return MERCADORIAS;
    }
}
//arquivo: mercadoria.ts
export class Mercadoria{
    codigo: string;
    mercadoria: string
}
//arquivo contrato.service.ts
import {Http,Headers} from '@angular/http';
import {Injectable} from '@angular/core';
import {ContratoComponent} from './contrato.component';
import {Mercadoria} from '../mercadoria/mercadoria';
import {Observable} from 'rxjs';
import {DatePipe} from '@angular/common';

@Injectable()
export class ContratoService{

    http: Http;
    headers:Headers;
    url:string = 'http://www.bigminds.io/FuturamaWS';


    constructor(http:Http){
        this.http=http;
        this.headers = new Headers();
        this.headers.append('Content-type','application/json');


    }

    //movements
    buscaContrato(codigo:string):Observable<any>{
        console.log('searching contrato....');
        return this.http.get(this.url+'/historico/'+codigo).map(res=>res.json());
    }

    private dateFormat(date) {
        var d = date.getDate();
        var m = date.getMonth() + 1;
        var y = date.getFullYear();
        return ''+ (d <= 9 ? '0' + d : d)+ (m<=9 ? '0' + m : m) + y;
    }

}

Entretanto, se eu instanciar a classe e atribuir os valores os metodos retornam o valor desejado. Ex:

        let movimento = new Movimento();
        movimento.fechamento=3500;
        movimento.maxima=3550;
        movimento.minima=3000;

        console.log('frequencia '+movimento.frequencia);
        console.log('alvo '+movimento.alvo);
        console.log('grafico '+movimento.grafico);

Thanks guys!

17 respostas

Em nenhum momento no seu método pesquisar vejo você criando uma instância de Movimento.

Se puder indicar a linha do problema ajuda. Tive dificuldade para compreender deu código e toda ajuda extra ajuda.

Oi Flávio blz? Eu não coloquei o codigo da view, perdão. Posso tentar explicar: tenho 2 services para prover os nomes das mercadorias e o histórico dos contratos, que é um array de Movimento. Na view da consultaComponent o usuário informa um código de contrato e uma data, a partir disso obtenho a mercadoria e procuro o histórico desse contrato renderizando numa tabela.

O código está compilando e rodando. O erro é que quando chamo esses métodos na view não obtenho nenhum valor, mas o restante dos valores como máxima, mínima,fechamento, data, volume são renderizados normalmente.

Realmente eu não instancio nenhum Movimento, estou usando o retorno do service e atribuindo ao this.historico

Pensei que o Angular os instanciava como objetos dessa classe Movimento. São um outro tipo de objeto? Pois se forem acho que preciso iterar sobre a coleção e criar um Movimento() para cada elemento. Tem alguma maneira do Angular fazer isso por mim? Lembro que no curso fizemos isso com FotoComponent, mas não tinha nenhum metodo getter, apenas propriedades dos objetos json.

.subscribe(historico=>{
            console.log('contrato localizado...');
            this.historico=historico;
        }, erro => console.log(erro))

Será que se transformar o Movimento em um @Component o angular passa a instanciar ou to viajando?

Obrigado.

Angular vai te retornar da Api um json desprovido de tipo.

Faça um map depois de subscribe para converter retorno para instâncias de Movimentacao.

Inclusive vc nem usa res.json() que ensino curso. Você fez os dois até o fim?

EDIT: vc fez sim, é que no smarphone eu não consegui ler!

Vou apontar as mudanças no código já já. ...

Bom, eu vou tentar focar a solução, pois continuo tendo dificuldades em entender seu código. Por exemplo, você tem o método buscaContrato no seu serviço que pelo nome eu espero que retorne um objeto, mas quando você usa o método você esta trabalhando com uma lista, mas chamou de histórico.

Mesmo sem entender o que você deseja (eu gosto de me basear no código (tudo bem que você me explicou) só olhando seu código, você precisa alterá-lo da seguinte forma. Seu método buscaContrato do teu serviço deve retornar uma lista do tipo Movimento. Eu estou assumindo que é lista porque você faz forEach no retorno desse método.

Alterando seu método buscaContrato:

    buscaContrato(codigo:string):Observable<Movimento>{
        console.log('searching contrato....');
        return this.http
            .get(this.url+'/historico/'+codigo)
            .map(res=>res.json())
            .map(dado => {
                let movimento = new Movimento();
                movimento.frequencia = dado.frequencia;
                movimento.grafico = dado.grafico;
                movimento.alvo = dado.alvo;
                return movimento;
            });
    }

Acredito que essa parte solucione seu problema. Veja que agora você tem uma lista com instância de Movimentoe objetos dessa instância possuem seus getters.

Sucesso e bom estudo.

Os nomes ficam meio confusos mesmo pois a nomenclatura é chata. O Histórico do contrato é formado pelas movimentações diárias. Cada movimentação tem uma cotação maxima, minima,etc. O histórico é por tanto um array contendo os movimentos de cada dia de negociação (pregão da bolsa). O povo chama assim, não vou contrariar rsrs. Mas você tem razão quanto ao nome dos métodos, vou adequar isso pra não ficar tão obscuro. Entendi agora que realmente preciso instanciar uma classe, fiz diferente do seu exemplo, por que frequenca, grafico e alvo sao os dados que nao vem do werbservice, por isso que criei um getter na classe. Entretanto temos um erro, ja que preciso devolver um Movimento[], agora estou devolvendo apenas um objeto Movimento. Veja la no tipo de retorno do método, deveriamos usar Movimento[], já que o consulta.component espera um array. Como fazer para retornar um array de Movimento? Tentei vasculhar algum exemplo mas não localizei nada.

buscaHistoricoContrato(codigo:string):Observable<Movimento>{
        console.log('searching contrato....');
        return this.http.get(this.url+'/historico/'+codigo)
        .map(res=>res.json())
        .map(dado=>{
            let movimento = new Movimento();
            movimento.data=dado.data;
            movimento.fechamento=dado.fechamento;
            movimento.variacao=dado.variacao;
            movimento.variacao_pct=dado.variacao_pct;
            movimento.maxima=dado.maxima;
            movimento.minima=dado.minima;
            movimento.volume=dado.volume;
            return movimento;
        });
    }

Veja que o tipo agora é Movimento[] e não Movimento:

buscaHistoricoContrato(codigo:string):Observable<Movimento[]>{
        console.log('searching contrato....');
        return this.http.get(this.url+'/historico/'+codigo)
        .map(res=>res.json())
        .map(dado=>{
            let movimento = new Movimento();
            movimento.data=dado.data;
            movimento.fechamento=dado.fechamento;
            movimento.variacao=dado.variacao;
            movimento.variacao_pct=dado.variacao_pct;
            movimento.maxima=dado.maxima;
            movimento.minima=dado.minima;
            movimento.volume=dado.volume;
            return movimento;
        });
    }

Na primeira resposta estava sem os colchetes. Ao inserir os colchetes, obtenho um erro de compilação. :(

Como ajusto seu método esta correto. Se deu erro de compilação, é na ponta que usa o método. Mas qual erro? Em que lugar?

Eulen? Tem a mensagem de erro para compartilhar?

Oi Fávio, o erro de compilação ocorre no método mesmo e não na origem da chamada. Se retiro os colchetes o serivce compila mas obtenho erro na ponta que evoca o método.

[ts]
Type 'Observable<Movimento>' is not assignable to type 'Observable<Movimento[]>'.
  Type 'Movimento' is not assignable to type 'Movimento[]'.
    Property 'length' is missing in type 'Movimento'.
let movimento: Movimento

Essa mensagem é na classe que usa o método do serviço quando o método usa Observable<Movimento[]>?

Mostra a classe que invoca o metodo buscaContrato.

O erro de compilação ocorre no service. Por algum motivo o útlimo map() está retornando um Observable e não Observable. Se eu alterar o retorno para Observable o erro de compilação desaparace, mas claro irá aparece um outro erro na classe ConsultaComponent que espera um array.

Obrigado pela disponbilidade em ajudar.

//arquivo: consulta.component.ts
import {Component,Input,OnInit} from '@angular/core';

import { ContratoService } from '../contrato/contrato.service';
import { Mercadoria} from '../mercadoria/mercadoria';
import { MercadoriaService} from '../mercadoria/mercadoria.service';
import { Contrato } from '../contrato/contrato';
import {FormGroup,FormBuilder,Validators } from '@angular/forms';
import {Movimento} from './movimento'


@Component({
    moduleId:module.id,
    selector:'consulta',
    templateUrl:'./consulta.component.html',
    providers:[ContratoService,Movimento,MercadoriaService]
})
export class ConsultaComponent implements OnInit{

    codigo:string;
    data:string;
    mercadoria: Mercadoria;
    historico: Movimento[];
    mercadorias: Mercadoria[];
    mensagem:string='';

    constructor(
            private contratoService:ContratoService,
            private mercadoriaService:MercadoriaService
    ){}

    ngOnInit(): void {
        this.mercadorias = this.mercadoriaService.getMercadorias();
        this.mercadoria = new Mercadoria();
        this.historico=[];
    }

    pesquisar(event){
        event.preventDefault();
        let mercadoria =this.getMercadoriaByCode(this.codigo.substr(0,3)); 
        this.mercadoria=mercadoria;
        this.contratoService.buscaHistoricoContrato(this.codigo)
        .subscribe(historico=>{
            console.log('contrato localizado...');
            this.historico=historico;
        }, erro => console.log(erro))

    }
    private getMercadoriaByCode(code):any {
        return this.mercadorias.filter(data => data.codigo == code)
    }

}
//arquivo: contrato.service.ts

import {Http,Headers} from '@angular/http';
import {Injectable} from '@angular/core';
import {Movimento} from '../consulta/movimento';
import {Observable} from 'rxjs';
import {DatePipe} from '@angular/common';

@Injectable()
export class ContratoService{

    http: Http;
    headers:Headers;
    url:string = 'http://www.bigminds.io/FuturamaWS';

    constructor(http:Http){
        this.http=http;
        this.headers = new Headers();
        this.headers.append('Content-type','application/json');
    }

    //movements
    buscaHistoricoContrato(codigo:string):Observable<Movimento[]>{
        console.log('searching contrato....');
        return this.http.get(this.url+'/historico/'+codigo)
        .map(res=>res.json())
        .map(dado=>{
            let movimento = new Movimento();
            movimento.data=dado.data;
            movimento.fechamento=dado.fechamento;
            movimento.variacao=dado.variacao;
            movimento.variacao_pct=dado.variacao_pct;
            movimento.maxima=dado.maxima;
            movimento.minima=dado.minima;
            movimento.volume=dado.volume;
            return movimento;
        });
    }

    private dateFormat(date) {
        var d = date.getDate();
        var m = date.getMonth() + 1;
        var y = date.getFullYear();
        return ''+ (d <= 9 ? '0' + d : d)+ (m<=9 ? '0' + m : m) + y;
    }

}

Bom, não sei a causa. Para resolver, coloque Observable<any[]>. Uma solução paliativa, mas você não terá autocomplete na outra ponta.

solução!

O erro persiste, pois continuo tentando retonar um array e o último map() retorna um único elemento. Por enquanto vou instanciar os objetos após receber o json do service. Está funcionando mas não é o ideal.

Obrigado pela paciência e ajuda Flávio, seus cursos são muito bons. Também estou gostando muito do curso de Javascript avançado com ES6.

 pesquisar(event){
        event.preventDefault();
        let mercadoria =this.getMercadoriaByCode(this.codigo.substr(0,3)); 
        this.mercadoria=mercadoria;
        this.contratoService.buscaHistoricoContrato(this.codigo)
        .subscribe(historico=>{
            console.log('contrato localizado...');
            let res:Movimento[] =[];
            historico.forEach(dado=>{
                let movimento = new Movimento();
                movimento.data=dado.data;
                movimento.fechamento=dado.fechamento;
                movimento.variacao=dado.variacao;
                movimento.variacao_pct=dado.variacao_pct;
                movimento.maxima=dado.maxima;
                movimento.minima=dado.minima;
                movimento.volume=dado.volume;
                res.push(movimento);
            });
            this.historico=res;
        }, erro => console.log(erro))

    }

Beleza. Se eu descobrir algo eu ressuscito aqui o post.