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

Erro toLowerCase

Olá! Após realizar o exercício de cadastro de fotos a aplicação começou a apresentar o seguinte erro:

core.umd.js:3462 EXCEPTION: Error in http://localhost:3000/app/listagem/listagem.component.html:23:12 caused by: Cannot read property 'toLowerCase' of undefined

E com isso as fotos não aparecem mais na listagem. Porém, notei que no console mostra que foram adicionados dados no banco como mostro abaixo:

Adicionado com sucesso: x7aoki73WcGPEfmw Adicionado com sucesso: WR5XHw5FjIHq81Mw Adicionado com sucesso: 9LoRQM9fLv9M4aUF

Alguém pode me ajudar?

Arquivo listagem.component.html

<div class="jumbotron">
<h1 class="text-center">AluraPic</h1>
</div>

<div class="container">

<div class="row">
        <div class="col-md-12">
            <form>
                 <div class="input-group">
                    <span class="input-group-btn">
                        <a [routerLink] = "['/cadastro']" class="btn btn-primary">
                            Nova foto
                        </a>
                    </span>
                    <input #textoProcurado (keyup) = "0" class="form-control" placeholder="filtrar pelo título da foto">
                </div> 
            </form>
        </div> <!-- fim col-md-12 -->
    </div> <!-- fim row -->
    <br>

    <div class="row">
    <painel *ngFor="let foto of fotos | filtroPorTitulo: textoProcurado.value " titulo="{{foto.titulo | uppercase}}" class="col-md-2">
        <foto url="{{foto.url}}" titulo="{{foto.titulo}}"></foto>
    </painel>    
    </div> <!-- fim row -->
</div>

arquivo listagem.component.ts

import { Component } from '@angular/core';
import { Http } from '@angular/http'

@Component ({
    moduleId: module.id,
    selector: 'listagem', 
    templateUrl: './listagem.component.html'
})
export class ListagemComponent {

    fotos: Object[] = [];

    constructor(http: Http){

        http
        .get('v1/fotos')
        .map (res => res.json())
        .subscribe(fotos => {
            this.fotos = fotos; 
            console.log(this.fotos);
        }, erro => console.log (erro));
    }
 }

arquivo foto.pipe

import { Pipe, PipeTransform } from "@angular/core";
import { FotoComponent } from './foto.component';

@Pipe ({
    name: 'filtroPorTitulo'
})

export class filtroPorTitulo implements PipeTransform {

    transform(fotos: FotoComponent[], digitado: string) {

        digitado = digitado.toLowerCase();
        return fotos.filter ( foto => foto.titulo.toLowerCase().includes (digitado))


        //console.log(fotos);
        //console.log(digitado);
    }

}
26 respostas

Você precisa colar o código que você fez a última alteração para que possamos ver. Cole o código de ListageComponente e também do seu template. Esse erro, que é um erro de JavaScript comum, indica que você esta chamando lowerCase de alguém que não existe.

Aguardamos seu código.

listagem.component.html

<div class="jumbotron">
<h1 class="text-center">AluraPic</h1>
</div>

<div class="container">

<div class="row">
        <div class="col-md-12">
            <form>
                 <div class="input-group">
                    <span class="input-group-btn">
                        <a [routerLink] = "['/cadastro']" class="btn btn-primary">
                            Nova foto
                        </a>
                    </span>
                    <input #textoProcurado (keyup) = "0" class="form-control" placeholder="filtrar pelo título da foto">
                </div> 
            </form>
        </div> <!-- fim col-md-12 -->
    </div> <!-- fim row -->
    <br>

    <div class="row">
    <painel *ngFor="let foto of fotos | filtroPorTitulo: textoProcurado.value " titulo="{{foto.titulo | uppercase}}" class="col-md-2">
        <foto url="{{foto.url}}" titulo="{{foto.titulo}}"></foto>
    </painel>    
    </div> <!-- fim row -->
</div>

arquivo listagem.component.ts

import { Component } from '@angular/core';
import { Http } from '@angular/http'

@Component ({
    moduleId: module.id,
    selector: 'listagem', 
    templateUrl: './listagem.component.html'
})
export class ListagemComponent {

    fotos: Object[] = [];

    constructor(http: Http){

        http
        .get('v1/fotos')
        .map (res => res.json())
        .subscribe(fotos => {
            this.fotos = fotos; 
            console.log(this.fotos);
        }, erro => console.log (erro));
    }
 }

arquivo foto.pipe

import { Pipe, PipeTransform } from "@angular/core";
import { FotoComponent } from './foto.component';

@Pipe ({
    name: 'filtroPorTitulo'
})

export class filtroPorTitulo implements PipeTransform {

    transform(fotos: FotoComponent[], digitado: string) {

        digitado = digitado.toLowerCase();
        return fotos.filter ( foto => foto.titulo.toLowerCase().includes (digitado))


        //console.log(fotos);
        //console.log(digitado);
    }

}

Posta para mim o código de FotoComponent. Estou achando que você não inicializou os valores das propriedades. É isso que leva ao erro que você esta tendo.

foto.component.ts

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

@Component ({
    moduleId: module.id,
    selector:'foto',
    templateUrl: './foto.component.html'

})

export class FotoComponent {
    @Input() titulo: string;
    @Input() url: string;
    descricao: string; 
}

Oi Nuno, então, faça assim:

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

@Component ({
    moduleId: module.id,
    selector:'foto',
    templateUrl: './foto.component.html'

})
export class FotoComponent {
    @Input() titulo: string = '';
    @Input() url: string = '';
    descricao: string = ''; 
}

Depois, veja se o erro continua ou foi resolvido. No vídeo, em alguma parte dele, talvez no anterior, eu faço isso.

Aguardo seu retorno meu aluno.

Lembro dessa parte sim . Mas continua com o mesmo erro. minha listagem de fotos não renderiza na tela.

EXCEPTION: Error in http://localhost:3000/app/listagem/listagem.component.html:23:12 caused by: Cannot read property 'toLowerCase' of undefined
ErrorHandler.handleError @ core.umd.js:3462
next @ core.umd.js:6924
schedulerFn @ core.umd.js:6172
SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238
SafeSubscriber.next @ Subscriber.ts:190
Subscriber._next @ Subscriber.ts:135
Subscriber.next @ Subscriber.ts:95
Subject.next @ Subject.ts:61
EventEmitter.emit @ core.umd.js:6164
onError @ core.umd.js:6388
onHandleError @ core.umd.js:6263
ZoneDelegate.handleError @ zone.js:196
Zone.runTask @ zone.js:128
ZoneTask.invoke @ zone.js:293
core.umd.js:3464 ORIGINAL EXCEPTION: Cannot read property 'toLowerCase' of undefined
ErrorHandler.handleError @ core.umd.js:3464
next @ core.umd.js:6924
schedulerFn @ core.umd.js:6172
SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238
SafeSubscriber.next @ Subscriber.ts:190
Subscriber._next @ Subscriber.ts:135
Subscriber.next @ Subscriber.ts:95
Subject.next @ Subject.ts:61
EventEmitter.emit @ core.umd.js:6164
onError @ core.umd.js:6388
onHandleError @ core.umd.js:6263
ZoneDelegate.handleError @ zone.js:196
Zone.runTask @ zone.js:128
ZoneTask.invoke @ zone.js:293
core.umd.js:3467 ORIGINAL STACKTRACE:
ErrorHandler.handleError @ core.umd.js:3467
next @ core.umd.js:6924
schedulerFn @ core.umd.js:6172
SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238
SafeSubscriber.next @ Subscriber.ts:190
Subscriber._next @ Subscriber.ts:135
Subscriber.next @ Subscriber.ts:95
Subject.next @ Subject.ts:61
EventEmitter.emit @ core.umd.js:6164
onError @ core.umd.js:6388
onHandleError @ core.umd.js:6263
ZoneDelegate.handleError @ zone.js:196
Zone.runTask @ zone.js:128
ZoneTask.invoke @ zone.js:293
core.umd.js:3468 TypeError: Cannot read property 'toLowerCase' of undefined
    at eval (http://localhost:3000/app/foto/foto.pipe.js:15:65)
    at Array.filter (native)
    at filtroPorTitulo.transform (http://localhost:3000/app/foto/foto.pipe.js:15:22)
    at eval (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:5721:26)
    at _View_ListagemComponent0.detectChangesInternal (ListagemComponent.ngfactory.js:226:128)
    at _View_ListagemComponent0.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9566:18)
    at _View_ListagemComponent0.DebugAppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9671:48)
    at _View_ListagemComponent_Host0.AppView.detectViewChildrenChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9592:23)
    at _View_ListagemComponent_Host0.AppView.detectChangesInternal (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9577:18)
    at _View_ListagemComponent_Host0.AppView.detectChanges (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:9566:18)
ErrorHandler.handleError @ core.umd.js:3468
next @ core.umd.js:6924
schedulerFn @ core.umd.js:6172
SafeSubscriber.__tryOrUnsub @ Subscriber.ts:238
SafeSubscriber.next @ Subscriber.ts:190
Subscriber._next @ Subscriber.ts:135
Subscriber.next @ Subscriber.ts:95
Subject.next @ Subject.ts:61
EventEmitter.emit @ core.umd.js:6164
onError @ core.umd.js:6388
onHandleError @ core.umd.js:6263
ZoneDelegate.handleError @ zone.js:196
Zone.runTask @ zone.js:128
ZoneTask.invoke @ zone.js:293

Mesmo inicializando as propriedades ? Pode colar novamente seu FotoComponent com a alteração ?

Então, o valor que você esta digitando não esta entrando no pipe, por isso que é undefined. Você esta usando a mesma versão do Angular do curso ou fez alguma mudança. Só para eu me situar.

Sim, é a mesma versão.

Agora você esta com problema em AppModule. Deve ter importando algo que não existe, algum caminho errado o TypeScript reclamou.

Cole o código do seu AppModule.

Você esta programando o TypeScript rodando no seu terminal? Se programar sem e depois ativá-lo, caso haja erro no seu código ele não funcionará. Você só pode programar com o serviço ligado no terminal.

Aguardo seu código de AppModule.

No visual studio ele diz que não tem nenhum mesmo exportado de ListagemComponent.

import 'rxjs/add/operator/map';

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
import { FotoModule } from './foto/foto.module';
import { PainelModule } from './painel/painel.module';
import {HttpModule} from '@angular/http';

import { CadastroComponent } from './cadastro/cadastro.component';
import { ListagemComponent } from './listagem/listagem.component';

import { routing } from './app.rout';

import { FormsModule } from '@angular/forms';


@NgModule({
  imports:      [ BrowserModule, FotoModule, HttpModule, PainelModule, routing, FormsModule ],
  declarations: [ AppComponent, CadastroComponent, ListagemComponent ],
  bootstrap:    [ AppComponent ]
})
 export class AppModule { }

Tem uma coisa estranha aqui:

import { routing } from './app.rout';

Você mudou o nome do arquivo para app.rout? Eu não uso esse nome de arquivo durante o curso. Você mudou mais algum nome? Se mudou, tem que trocar o nome nome em todos os lugares.

Agora, eu preciso do seu FotoModule, porque é lá que você registra o pipe e tals.

import { NgModule } from '@angular/core';
import { FotoComponent } from './foto.component';
import { filtroPorTitulo } from './foto.pipe';

@NgModule ({
    declarations: [ FotoComponent, filtroPorTitulo ],
    exports: [ FotoComponent, filtroPorTitulo ]

})

export class FotoModule { }

E o import do arquivo de rotas? É esse nome mesmo que você criou ou foi erro de digitação?

Foi erro de digitação. Seria app.routes.ts . Posso renomear?

Qual é o nome do arquivo físico. É app.routes.ts que existe na sua máquina? Qual o nome?

app.rout.ts

Então, deixa assim. Há outros lugares que você não seguiu o padrão. Então, você tem o projeto completo no github? Vou ter que olhar cada arquivo , fazer um trabalho de arqueólogo porque você esta com dependência circular (acredito eu) e isso pode estar em alguns dos seus arquivos pelo o último erro que você me passou.

Tenho o projeto no github.

Atualiza ele no github e me passa o link,.

Descobri o problema. O problema esta na gravação. Durante a gravação, você esta salvando apenas o ID da foto, não esta enviando os outros dados. Dai, quando você volta para a tela de listagem, quando ele tenta usar o pipe e ler a propriedade .titulo do objeto foto que veio do servidor ele não tem.

Você precisará apagar seu arquivo alurapic/server/data.db. Se quiser voltar com os dados que já tinham lá, basta pegar o data.db de um projeto mais antigo e jogar por cima do seu.

Fazer isso resolve o problema da listagem. Mas vai continuar dando pau, porque por algum motivo, não sei se você já corrigiu, não esta enviando todos os dados do objeto. Sendo assim, antes de continuar, você precisa colar para mim o código de CadastroComponent e também do seu template para ver se esta tudo OK.

É por isso que você começou a ter problema depois do cadastro, pois cadastrou informações indevidas gravando no backend apenas o ID. (na verdade, você não deve ter enviado dado algum, o servidor aceitou e gerou um ID bobo lá).

Aguardo seu código. Viu, demora um pouco mas eu sempre descubro! hehehe

Ei, não precisa enviar mais nada, tenho seu repo do git! Duh! hehehe

Vou olhar aqui e já te falo!

solução!

Seu CadastroComponent esta com problema. Olha como esta seu código hoje:


    cadastrar(event) {
        event.preventDefault();
        console.log (this.foto);

        let headers = new Headers();

        headers.append('Content-Type', 'appication/json');

        //this.http.post('v1/fotos', JSON.stringify(this.foto), { headers : headers })

        this.http.post('v1/fotos', this.foto, { headers: headers })

        .subscribe(() => {

            this.foto = new FotoComponent(); 

            console.log ('Foto salva com sucesso');

        }, erro => console.log(erro));

    }

Você escreveu errado o content type. O correto é application/json.

Outro ponto, você comentou, não sei por qual motivo, uma linha importante que faz o JSON.stringify! Não pode removê-la.

O código correto fica assim:


    cadastrar(event) {
        event.preventDefault();
        console.log (this.foto);

        let headers = new Headers();

        headers.append('Content-Type', 'application/json');

        this.http.post('v1/fotos', JSON.stringify(this.foto), { headers : headers })

        .subscribe(() => {

            this.foto = new FotoComponent(); 

            console.log ('Foto salva com sucesso');

        }, erro => console.log(erro));

    }

Lembre-se que você precisa, com o servidor parado, apagar o arquivo que lhe falei no post anterior.

Agora esta tudo certo.