Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
10
respostas

Mostrar imagem da url com problemas. Aparecendo undefined antes de informar a url

Olá, na última aula do curso parte 1, é feito um link para que quando eu informe a url da imagem, a imagem já apareça ao lado do formulário.

O que ocorre é que enquanto eu não tiver informado a url, ele mostra "undefined" onde deveria aparecer a foto.

Notei que no vídeo não aconteceu isso com o instrutor. É alguma configuração do navegador?

Conferi aqui, e acredito que meu código esteja igual ao da aula.

<div class="container">
    <h1 class="text-center">
        {{foto.titulo}}
    </h1>
    <form [formGroup]="meuForm" class="row" (submit)="cadastrar($event)">
        <div class="col-md-6">
            <div class="form-group">
                <label for="">
                    Título
                </label>

                <input type="text" formControlName="titulo" name="titulo" [(ngModel)]="foto.titulo" class="form-control" autocomplete="off">
                <div *ngIf="meuForm.controls.titulo.invalid">
                    <!-- Pega a validação somente do Validators.titulo -->
                    <span *ngIf="meuForm.controls.titulo.errors.required" class="form-control alert-danger">Título obrigatório</span>
                    <span *ngIf="meuForm.controls.titulo.errors.minlength" class="form-control alert-danger">Mínimo de 4 caracteres</span>
                </div>
            </div>
            <div class="form-group">
                <label for="">
                    URL
                </label>
                <input type="text" formControlName="url" name="url" [(ngModel)]="foto.url" class="form-control" autocomplete="off">
                <span *ngIf="meuForm.controls.url.invalid" class="form-control alert-danger">URL obrigatória</span>
            </div>
            <div class="form-group">
                <label for="">
                    Descrição
                </label>
                <textarea class="form-control" formControlName="descricao" name="descricao" [(ngModel)]="foto.descricao" autocomplete="off"></textarea>
            </div>

            <button type="submit" class="btn btn-primary" [disabled]="meuForm.invalid">Salvar</button>
            <a [routerLink]="['']" class="btn btn-primary">Voltar</a>
            <hr>
        </div>
        <div class="col-md-6">
            <foto [url]="foto.url" [titulo]="foto.titulo"></foto>
        </div>
    </form>
</div>
10 respostas

Poste o código dos seus componentes. Uma img com url inválida exibe seu alt. Se está saindo undefined é problema no modelo. Teria que exibir o nome da foto.

foto.component

import { Component, Input } from '@angular/core'; // Input serve para que o meu component possa receber parâmetros, no caso titulo e url

@Component ({
    moduleId: module.id, // diz que o component está na mesma pasta do module, neste caso, o Angular vai procurar na pasta foto, que contém o component E o module
    selector: 'foto', // o nome da tag html que chama o component
    templateUrl:'./foto.component.html'
})
export class FotoComponent
{
    // titulo e url são parâmetros que recebem valores passados através do selector no html: <foto url="img/leao.jpg" titulo="Leão"></foto>
    @Input() titulo : string;
    @Input() url : string;

    // Descricao não recebe o @Input() pq nesse componente, somente o titulo e a url serão recebidos como parâmetros enviados de outros lugares
    descricao : string;
}

E o componente de cadastro?

Você não inicializou as propriedades com valor default em FotoComponent. Se fizer new FotoComponent() ficarão undefined.

Isso era para ter sido feito antes.

OK.

Fiz a inicialização das propriedades, mas ainda ocorre o problema.

foto.component

import { Component, Input } from '@angular/core'; // Input serve para que o meu component possa receber parâmetros, no caso titulo e url

@Component ({
    moduleId: module.id, // diz que o component está na mesma pasta do module, neste caso, o Angular vai procurar na pasta foto, que contém o component E o module
    selector: 'foto', // o nome da tag html que chama o component
    templateUrl:'./foto.component.html'
})
export class FotoComponent
{
    // titulo e url são parâmetros que recebem valores passados através do selector no html: <foto url="img/leao.jpg" titulo="Leão"></foto>
    @Input() titulo : string = '';
    @Input() url : string = '';

    // Descricao não recebe o @Input() pq nesse componente, somente o titulo e a url serão recebidos como parâmetros enviados de outros lugares
    descricao : string = '';
}

cadastro.component

import { Component } from '@angular/core';
import { FotoComponent } from '../foto/foto.component';
import { Http, Headers } from '@angular/http';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; // Validação de formulários

@Component ({
    moduleId    : module.id,
    selector    : 'cadastro',
    templateUrl : './cadastro.component.html'
})
export class CadastroComponent 
{
    foto : FotoComponent = new FotoComponent();
    http : Http;
    meuForm : FormGroup

    constructor (http : Http, formBuilder : FormBuilder)
    {
        this.http = http;
        this.meuForm = formBuilder.group ({
            titulo : ['', Validators.compose([Validators.required, Validators.minLength(4)])],
            url : ['', Validators.required],
            descricao : [''] // mesmo a descricao nao sendo required, ela tem de estar no group
        });
    }

    cadastrar (event)
    {
        // Evita que o formulário faça o submit recarregando a página
        event.preventDefault();

        console.log(this.foto);

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');

        // Faz um POST para o servidor, enviando um JSON para lá
        this.http
            .post('v1/fotos', JSON.stringify(this.foto), { headers : headers })
            .subscribe(() => { // () pq o servidor não devolve nada. Caso tivesse alguma resposta, essa resposta seria passada antes do =>
                this.foto = new FotoComponent(); // Cria uma nova foto, vazia. Posi dessa forma, quando voltar pra view do formulário, o formulário não estar preenchido com os dados da última foto cadastrada
                console.log('Foto salva com sucesso');
            }, error => console.log('Ocorreu um erro'));
    }
}

Bom, seu código esta indicando que esta tudo certo, mas você diz que ainda é exibido undefined, certo? Mesmo quando você digita na URL? Por algum motivo que desconheço olhando seu código, a propriedade ainda continua undefined, é como se ela não tivesse adotado o valor padrão. Fez isso com o compilador em tempo real do TypeScript ligado? Se não fizer, não vai adiantar.

Então, parece que era o compilador, que não estava ativado. Porém, com o compilador ativado, aparece o "alt" da imagem.

Link com o print de como fica: https://drive.google.com/open?id=0B3MW4r2fI9TBcER5SWlVMk5Wc0k

Uma dúvida surgiu: fiquei com a impressão agora de que para Angular 2 funcionar corretamente, o compilador de TypeScript deve estar ativado?

Como funciona isso em um ambiente de produção? Quando meu app com Angular estiver no ar, usando Apache e PHP como o back end?

solução!

O resultado do seu código agora é o esperado, funcionou. Vamos aos esclarecimentos meu aluno, para você ficar cangaceiro no assunto.

Você só precisa do compilador do TypeScript em tempo de compilação, enquanto desenvolve. Depois que o projeto estiver pronto, os arquivos compilados são empacotados e colocados em qualquer servidor.

Quando lancei esse curso, o Angular CLI era Beta e BUGADÃO. Mas hoje, se você for criar um projeto do zero, use o Angular CLI. Ele, além de criar um server para desenvolvimento, possui comandos que empacotam sua aplicação. No final, é sempre gerado um arquivo js chamado bundle.js e basta levá-lo como index.html para um servidor web do seu interesse.

Eu amarrei essa explicação muito bem no curso de Vue.js, porque ele já vem com CLI e é bem estável. Pode parecer estranho eu falar isso, mas seria bem interessante que você assistisse os vídeo que vou lhe passar. O conceito é o mesmo com o Angular CLI e o Angular.

https://cursos.alura.com.br/course/vue-parte2/task/23715

Não vai tomar muito o seu tempo, mas vai dar uma clareada muito boa nessa questão.

Aliás, se você não fechou com Angular ainda, talvez dar uma chance para o Vue também seja interessante.

Espero ter ajudado, meu aluno!

Ajudou muito sim!

Obrigado pela dedicação.

Quanto ao Angular vs Vue, estou indo de Angular, pois pretendo depois fazer o curso de Ionic 2.

Mas já ouvi falar bem do Vue tbm.

Obrigado.

Então, vou fazer um spoiler. Em breve teremos um curso só de TypeScript. Esse curso ajudará o aluno nos cursos de Angular, inclusive no curso de Ionic2.

Assim que sair, sugiro cursá-lo para ficar ainda melhor nessas tecnologias.

Quando chegar em Ionic2, verá que muitos dos conceitos que aprendeu no curso do Angular serão aplicados, por isso ele é pré-requisito. Já adianto que no final do curso de Ionic2, eu ensino a migrar para o Ionic3.

Sucesso e bom estudo meu aluno!