Typeerror Cannot read Property 'name' of Undefined at Angular 4

Asked

Viewed 6,996 times

2

My application is working perfectly, the only thing wrong is taking this error message;

MidiaExibirComponent.html:13 ERROR TypeError: Cannot read property 'nome' of undefined
    at Object.eval [as updateRenderer] (MidiaExibirComponent.html:13)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:14693)
    at checkAndUpdateView (core.js:13807)
    at callViewAction (core.js:14153)
    at execComponentViewsAction (core.js:14085)
    at checkAndUpdateView (core.js:13808)
    at callViewAction (core.js:14153)
    at execComponentViewsAction (core.js:14085)
    at checkAndUpdateView (core.js:13808)
    at callWithDebugContext (core.js:15056)

Line 13 is this line of code;

<td>{{ cotas.USD.nome }}</td>

This is my full page;

<table class="table">
    <thead>
      <tr>

        <th scope="col">Moedas</th>
        <th scope="col">Valor</th>
        <th scope="col">Visualização</th>
      </tr>
    </thead>
    <tbody>
      <tr>

        <td>{{ cotas.USD.nome }}</td>
        <td>{{ cotas.USD.valor }}</td>
        <td>{{ cotas.USD.ultima_consulta }}</td>
      </tr>
      <tr>

          <td>{{ cotas.EUR.nome }}</td>
          <td>{{ cotas.EUR.valor }}</td>
          <td>{{ cotas.EUR.ultima_consulta }}</td>
      </tr>
      <tr>
          <td>{{ cotas.ARS.nome }}</td>
          <td>{{ cotas.ARS.valor }}</td>
          <td>{{ cotas.ARS.ultima_consulta }}</td>
      </tr>
      <tr>
          <td>{{ cotas.GBP.nome }}</td>
          <td>{{ cotas.GBP.valor }}</td>
          <td>{{ cotas.GBP.ultima_consulta }}</td>
      </tr>

      <tr>
          <td>{{ cotas.BTC.nome }}</td>
          <td>{{ cotas.BTC.valor }}</td>
          <td>{{ cotas.BTC.ultima_consulta }}</td>
      </tr>
    </tbody>
  </table>

That is the service;

import { Midia, Moedas } from './../core/model';

import { Http, Headers, URLSearchParams } from '@angular/http';
import { Injectable } from '@angular/core';

import 'rxjs/add/operator/toPromise';




@Injectable()
export class MidiaService {

  midiasUrl = 'http://localhost:8080/midia/midias';
  quotationURL = 'http://api.promasters.net.br/cotacao/v1/valores?moedas=USD,BTC,EUR,ARS,GBP&alt=json';

  constructor(private http: Http) { }



pesquisarUSD(): Promise<any> {
  return this.http.get(`${this.quotationURL}`)
  .toPromise()
 .then(response => response.json().valores);

}



}

And that’s the component;

import { MidiaService } from './../midia.service';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-midia-exibir',
  templateUrl: './midia-exibir.component.html',
  styleUrls: ['./midia-exibir.component.css']
})
export class MidiaExibirComponent implements OnInit {


cotas = [];

  constructor(private midiaService: MidiaService) { }

  ngOnInit() {


      this.pesquisar();
  }

  pesquisar() {
    this.midiaService.pesquisarUSD()
    .then(cotas => this.cotas = cotas);
  }



}

==============================================================

json file

{
    "status": true,
    "valores": {
        "USD": {
            "nome": "Dólar",
            "valor": 3.408,
            "ultima_consulta": 1523995502,
            "fonte": "UOL Economia - http://economia.uol.com.br/"
        },
        "EUR": {
            "nome": "Euro",
            "valor": 4.2171,
            "ultima_consulta": 1523995502,
            "fonte": "UOL Economia - http://economia.uol.com.br/"
        },
        "ARS": {
            "nome": "Peso Argentino",
            "valor": 0.1691,
            "ultima_consulta": 1523995502,
            "fonte": "UOL Economia - http://economia.uol.com.br/"
        },
        "GBP": {
            "nome": "Libra Esterlina",
            "valor": 4.8704,
            "ultima_consulta": 1523995502,
            "fonte": "UOL Economia - http://economia.uol.com.br/"
        },
        "BTC": {
            "nome": "Bitcoin",
            "valor": 27516,
            "ultima_consulta": 1524047408,
            "fonte": "Mercado Bitcoin - http://www.mercadobitcoin.com.br/"
        }
    }
}

===================================================== See verification code

.then(response => {
  console.log(response.json().valores);

});
}

console score;

inserir a descrição da imagem aqui

=====================================================================

   .then(cotas => {
    console.log(this.cotas = cotas);

  });

inserir a descrição da imagem aqui

How do I get this error message out?

  • The problem starts to show quota names that you don’t have, in the example of the question the quota USD. You have to try to see what you want to do in this case.

  • @wladyband Which of the objects is as Undefined? cotas or USD?

  • @LINQ if you observe my code quotas is a variable created in the component class of angula and USD is part of the attributes coming from json URL, I updated my post take a look there.

  • @wladyband It would not be: <td>{{ cotas.valores.USD.nome }}</td>

  • @Marcusvinicius values is already being declared in the service class as shown in the post.

  • @wladyband Make a console.log in quotas after receiving the value and show the result then

  • @LINQ I guess I didn’t need it because I had already released the result of Json, but even so I put it as requested, please check the update of my post.

  • @wladyband It was supposed to be console.log in quotas

  • @LINQ ready check again please I just updated

  • You are sure that the variables are visible in the view scope?

  • 2

    @wladyband edited the answer: https://answall.com/a/292300/3635

  • Good morning friend, in this excerpt, how is your variable ? search() { this.midiaService.searchUSD() . then(quotas => this.quotas = quotas); } "quotas" is declared where and how?

Show 7 more comments

4 answers

4

I had a similar problem, try to write the line that way:

<td>{{ cotas?.USD.nome }}</td> ou <td>{{ cotas.USD?.nome }}</td>
  • unfortunately it didn’t work

3


I had a similar problem and for me, develop a resolver in the route of the component solved my problem.

Implement a route:

example.routets.:

@Injectable({ providedIn: 'root' })
export class ExemploResolve implements Resolve<any> {
    constructor(private service: ExemploService) {}

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IExemplo> {
        const id = route.params['idExemplo'] ? route.params['idExemplo'] : null;
        if (id) {
            return this.service.find(id).pipe(
                filter((response: HttpResponse<Exemplo>) => response.ok),
                map((exemplo: HttpResponse<Exemplo>) => exemplo.body)
            );
        }
        return of(new Exemplo());
    }
}

export const exemploRoute: Routes = [
    {
        path: '',
        component: ExemploComponent,
        resolve: {
            pagingParams: JhiResolvePagingParams
        },
        data: {
            defaultSort: 'id,asc',
            pageTitle: 'Exemplos'
        },
    },
    {
        path: 'new',
        component: ExemploUpdateComponent,
        resolve: {
            projeto: ExemploResolve
        },
        data: {
          defaultSort: 'id,asc',
          pageTitle: 'Exemplos'
      },
  }
];

2

It’s probably because "view" is trying to display something that doesn’t exist yet, even before the HTTP request starts:

<td>{{ cotas.USD.nome }}</td>
<td>{{ cotas.USD.valor }}</td>
<td>{{ cotas.USD.ultima_consulta }}</td>

That is, the message:

Cannot read Property 'name' of Undefined

Says he tried to access the name of undefined, this means that: contas.USD, contas.EUR, etc, are non-existent keys within its object this.contas, what you could use is simply a *ngIf (https://angular.io/api/common/NgIf) to check if the value exists:

  <tr *ngIf="cotas.USD">
    <td>{{ cotas.USD.nome }}</td>
    <td>{{ cotas.USD.valor }}</td>
    <td>{{ cotas.USD.ultima_consulta }}</td>
  </tr>

  <tr *ngIf="cotas.EUR">
      <td>{{ cotas.EUR.nome }}</td>
      <td>{{ cotas.EUR.valor }}</td>
      <td>{{ cotas.EUR.ultima_consulta }}</td>
  </tr>

  <tr *ngIf="cotas.ARS">
      <td>{{ cotas.ARS.nome }}</td>
      <td>{{ cotas.ARS.valor }}</td>
      <td>{{ cotas.ARS.ultima_consulta }}</td>
  </tr>

  <tr *ngIf="cotas.GBP">
      <td>{{ cotas.GBP.nome }}</td>
      <td>{{ cotas.GBP.valor }}</td>
      <td>{{ cotas.GBP.ultima_consulta }}</td>
  </tr>

  <tr *ngIf="cotas.BTC">
      <td>{{ cotas.BTC.nome }}</td>
      <td>{{ cotas.BTC.valor }}</td>
      <td>{{ cotas.BTC.ultima_consulta }}</td>
  </tr>

You could also iterate the this.cotas with *ngFor= so you wouldn’t have to keep doing so much code repeating using let cota of cotas, thus cota will loop through USD, EUR, ARS, GBP and BTC:

<table class="table">
    <thead>
      <tr>

        <th scope="col">Moedas</th>
        <th scope="col">Valor</th>
        <th scope="col">Visualização</th>
      </tr>
    </thead>
    <tbody>

      <tr *ngFor="let cota of cotas">
          <td>{{ cota.nome }}</td>
          <td>{{ cota.valor }}</td>
          <td>{{ cota.ultima_consulta }}</td>
      </tr>

    </tbody>
  </table>

This helps to greatly decrease the code.

2

William’s response may work, but I’ll suggest an alternative:

In your service, let the method that makes the request return an Observable:

import 'rxjs/add/operator/map';
...
pesquisarUSD(): Observable<any> {
   return this.http.get(`${this.quotationURL}`).map(response => response.json().valores);
}

In its component, declare the member as:

import {  share } from 'rxjs/operators';
...
cotasAsync: Observable<{}>;

And on Oninit, search the service data like this:

this.cotasAsync = this.midiaService.pesquisar().pipe(share());

And in the view, do the object initialization check using the async pipe from Angular:

<table class="table" *ngIf="cotasAsync | async; let cota; else loading">
<thead>
  <tr>

    <th scope="col">Moedas</th>
    <th scope="col">Valor</th>
    <th scope="col">Visualização</th>
  </tr>
</thead>
<tbody>
  <tr>

    <td>{{ cota.USD.nome }}</td>
    <td>{{ cota.USD.valor }}</td>
    <td>{{ cota.USD.ultima_consulta }}</td>
  </tr>
  <tr>

      <td>{{ cota.EUR.nome }}</td>
      <td>{{ cota.EUR.valor }}</td>
      <td>{{ cota.EUR.ultima_consulta }}</td>
  </tr>
  <tr>
      <td>{{ cota.ARS.nome }}</td>
      <td>{{ cota.ARS.valor }}</td>
      <td>{{ cota.ARS.ultima_consulta }}</td>
  </tr>
  <tr>
      <td>{{ cota.GBP.nome }}</td>
      <td>{{ cota.GBP.valor }}</td>
      <td>{{ cota.GBP.ultima_consulta }}</td>
  </tr>

  <tr>
      <td>{{ cota.BTC.nome }}</td>
      <td>{{ cota.BTC.valor }}</td>
      <td>{{ cota.BTC.ultima_consulta }}</td>
  </tr>
</tbody>
</table>

Here are some suggestions: - If you are using Angular 4 or higher, switch to httpclient class instead of Http. The class Http is obsolete.

  • Anyway had to have one *ngIf=, right? So personally I think the use of Observable for specific case was to type "buy a tank to kill ants", maybe in more complex situations is interesting, but for something that is simple I do not think it takes so much.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.