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

Não aparecem as mensagens de erro no navegador

Não são exibidas mensagens de erro na hora de cadastrar uma nova oferta com dados errados ou em branco. Já comparei o código com o da aula várias vezes, mas não consegui identificar o problema. Alguém pode me ajudar? Segue o código:

<html xmlns="http://www.w3.org/1999/html" xmlns:v-bind="http://www.w3.org/1999/xhtml"
      xmlns:v-on="http://www.w3.org/1999/xhtml">
    <head th:replace="~{base :: head}"></head>
    <body onload="onLoad()">
        <div th:replace="~{base :: logo}"></div>

        <div class="container" id="ofertas">
            <div th:replace="~{base :: titulo('Faça sua oferta')}"></div>

            <div class="card mb-3" v-for="pedido in pedidos">

                    <div  class="card-header alert-dark" >{{pedido.nomeProduto}}</div>

                <div class="card-body">
                    <div class="row">
                        <div class="col-12 col-sm-8 mb-3">


                            <div>Produto</div> 
                            <div> <a class="form-control" v-bind:href="pedido.urlProduto">{{pedido.nomeProduto}}</a></div>

                            <div>Descrição</div>
                            <div>
                                <textarea disabled="disabled" class="form-control">{{pedido.descricao}}</textarea>
                            </div>
                            <div class="row mt-3">
                                <div class="col-md-5">
                                    Valor: <input v-bind:class="{'is-invalid':pedido.erros.valor!==''}" class="form-control" v-model="pedido.valorNegociado"/>
                                    <div v-if="pedido.erros.valor" class="invalid-feedback">
                                        {{pedido.erros.valor}}
                                    </div>
                                </div>

                                <div class="col-md-7">
                                    Data da entrega: <input v-bind:class="{'is-invalid':pedido.erros.dataDaEntrega!==''}" class="form-control" v-model="pedido.dataDaEntrega"/>
                                    <div v-if="pedido.erros.dataDaEntrega" class="invalid-feedback">
                                        {{pedido.erros.dataDaEntrega}}
                                    </div>
                                </div>
                            </div>
                            <div class="mt-2">
                                <label>Comentário</label>
                                <textarea class="form-control" v-model="pedido.comentario"></textarea>
                            </div>
                            <button disabled v-if="pedido.ofertaEnviada" class="btn btn-success mt-2">Oferta enviada</button>
                            <button v-else v-on:click="enviarOferta(pedido)" class="btn btn-primary mt-2">Enviar oferta</button>
                        </div>
                        <div class="col-12 col-sm-4">
                            <div>
                                <img class="img-thumbnail" v-bind:src="pedido.urlImagem"/>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <script>
            function onLoad(){

                var app = new Vue({
                    el: '#ofertas',
                    data: {
                        pedidos: []
                    },
                    mounted() {
                        axios
                                .get('http://localhost:8080/api/pedidos/aguardando')
                                .then(response => {
                                    response.data.forEach(pedido => {
                                        pedido.ofertaEnviada = false;
                                        pedido.erros = {
                                            valor: '',
                                            dataDaEntrega: ''
                                        }

                                    })
                                    this.pedidos = response.data

                                })
                    },
                    methods: {
                        enviarOferta: function (pedido){
                            pedido.erros = {
                                valor: '',
                                dataDaEntrega: ''
                            }
                            axios
                            .post('http://localhost:8080/api/ofertas', {
                                pedidoId: pedido.id,
                                valor: pedido.valorNegociado,
                                dataDaEntrega: pedido.dataDaEntrega,
                                comentario: pedido.comentario
                            })
                            .then(response => pedido.ofertaEnviada = true)
                            .catch(error => {
                                error.response.data.errors.forEach(error => {
                                    pedido.erros[error.field] = error.defaultMessage;
                                })
                            })
                        }
                    }
                })

            }
        </script>

        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    </body>
</html>

E aqui o que aparece no console ao tentar cadastrar uma oferta em branco:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

7 respostas

Olá! Testei o seu trecho do código aqui e parece estar tudo ok. Teria como postar aqui o seu código da classe OfertasRest e OfertaController?

Claro, seguem os códigos:

OfertasRest

package br.com.alura.mvc.mudi.api;

import br.com.alura.mvc.mudi.dto.RequisicaoNovaOferta;
import br.com.alura.mvc.mudi.model.Oferta;
import br.com.alura.mvc.mudi.model.Pedido;
import br.com.alura.mvc.mudi.repository.PedidoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Optional;

@RestController
@RequestMapping("/api/ofertas")
public class OfertasRest {

    @Autowired
    private PedidoRepository pedidoRepository;

    @PostMapping
    public Oferta criaOferta(@RequestBody @Valid RequisicaoNovaOferta requisicao) {

        Optional<Pedido> pedidoBuscado = pedidoRepository.findById(requisicao.getPedidoId());

        if (!pedidoBuscado.isPresent()){
            return null;
        }

        Pedido pedido = pedidoBuscado.get();

        Oferta novaOferta = requisicao.toOferta();

        novaOferta.setPedido(pedido);
        pedido.getOfertas().add(novaOferta);

        pedidoRepository.save(pedido);

        return novaOferta;
    }
}

OfertaController

package br.com.alura.mvc.mudi.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/oferta")
public class OfertaController {

    @GetMapping
    public String getFormularioParaOfertas(){
        return "oferta/home";
    }
}

Parece tudo ok também, desculpa o incômodo, mas poderia postar aqui o seu código da classe model Oferta?

Incômodo algum, agradeço a ajuda. Segue o código da classe Oferta:

package br.com.alura.mvc.mudi.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDate;

@Entity
public class Oferta {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private BigDecimal valor;

    private LocalDate dataDaEntrega;

    private String comentario;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.EAGER)
    private Pedido pedido;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public BigDecimal getValor() {
        return valor;
    }

    public void setValor(BigDecimal valor) {
        this.valor = valor;
    }

    public LocalDate getDataDaEntrega() {
        return dataDaEntrega;
    }

    public void setDataDaEntrega(LocalDate dataDaEntrega) {
        this.dataDaEntrega = dataDaEntrega;
    }

    public String getComentario() {
        return comentario;
    }

    public void setComentario(String comentario) {
        this.comentario = comentario;
    }

    public Pedido getPedido() {
        return pedido;
    }

    public void setPedido(Pedido pedido) {
        this.pedido = pedido;
    }
}

E da classe RequisiçãoNovaOferta:

package br.com.alura.mvc.mudi.dto;

import br.com.alura.mvc.mudi.model.Oferta;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class RequisicaoNovaOferta {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

    private Long pedidoId;

    //Um ou mais dígitos antes do ponto e depois do ponto espera 2 dígitos
    @Pattern(regexp = "^\\d+(\\.\\d{2})?$")
    @NotNull
    private String valor;

    @Pattern(regexp = "^\\d{2}/\\d{2}/\\d{4}$")
    @NotNull
    private String dataDaEntrega;

    private String comentario;

    public Long getPedidoId() {
        return pedidoId;
    }

    public void setPedidoId(Long pedidoId) {
        this.pedidoId = pedidoId;
    }

    public String getValor() {
        return valor;
    }

    public void setValor(String valor) {
        this.valor = valor;
    }

    public String getDataDaEntrega() {
        return dataDaEntrega;
    }

    public void setDataDaEntrega(String dataDaEntrega) {
        this.dataDaEntrega = dataDaEntrega;
    }

    public String getComentario() {
        return comentario;
    }

    public void setComentario(String comentario) {
        this.comentario = comentario;
    }

    public Oferta toOferta() {

        Oferta oferta = new Oferta();
        oferta.setComentario(this.comentario);
        oferta.setDataDaEntrega(LocalDate.parse(this.dataDaEntrega, formatter));
        oferta.setValor(new BigDecimal(this.valor));

        return oferta;
    }
}
solução!

Olá Raul! Acredito que eu tenha encontrado o problema. Vou marcar com comentários aqui as alterações a ser feitas:

Primeiro, no seu home.html do template oferta:

  methods: {
                        enviarOferta: function (pedido){
                            pedido.erros = {
                                valor: '',
                                dataDaEntrega: ''
                            }; <! --- Coloque um porto e vírgula aqui! ---> 
                            axios
                            .post('http://localhost:8080/api/ofertas', {
                                pedidoId: pedido.id,
                                valor: pedido.valorNegociado,
                                dataDaEntrega: pedido.dataDaEntrega,
                                comentario: pedido.comentario
                            })
                            .then(response => pedido.ofertaEnviada = true)
                            .catch(error => {
                                error.response.data.errors.forEach(error => {
                                    pedido.erros[error.field] = error.defaultMessage;
                                })
                            })
                        }
                    }
                });  <! --- Coloque um porto e vírgula aqui! ---> 

Na classe modelo Oferta:

@JsonIgnore
@ManyToOne(fetch = FetchType.**LAZY**) // Altere de EAGER para LAZY!
private Pedido pedido;

public Long getId() {
    return id;
}

aguardo retorno!

Eu não acharia esse último ponto e vírgula nunca hahaha tá funcionando, obrigado! Quanto ao FetchType eu tive que mudar de LAZY pra EAGER na classe Oferta e na lista de ofertas da classe Pedido porque, por algum motivo, se não fizer isso o formulário de "Faça sua oferta" para de funcionar depois das mudanças da última aula do curso. Também tive que colocar a anotação @Valid no método criaOferta de OfertaRest.

Valeu pela ajuda! Se tiver curiosidade de ver o código final tá no meu github: https://github.com/raul-lima/mudi

Print da tela de Faça Sua Oferta com as mensagens de erro por campo vazio

Fico feliz que tenha funcionado! Um abraço! :]