After request AJAX input does not return value to ManagedBean?

1

I am building an address registration form and I have implemented the combos for State and City respectively. They work in the usual way, with the combo of the city being filled according to the value selected by the state combo.

I have read a tutorial on how to implement this functionality, however I am having a very annoying problem regarding the mandatory fields and value assignment of the inputs to the ManagedBean. This is because the ajax event responsible for loading the city combo based on the state value works, however, after giving a submit in the registration form the city value is not set in the bean and JSF spits out a "Required field" .

I'm trying to find the cause ... but I have not found it yet.

My implementation is as follows:

address.xhtml

<f:view>
    <p:fieldset legend="Endereco">
        <h:panelGrid columns="2">
            <h:panelGrid columns="2">
                <p:outputLabel value="Logradouro: " id="lblLogradouro"
                    for="txtLogradouro" />
                <p:inputText value="#{enderecoBean.endereco.logradouro}"
                    id="txtLogradouro" style="width:435px;" required="true"
                    requiredMessage="É necessário preencher o campo Logradouro!" />
            </h:panelGrid>

            <h:panelGrid columns="2">
                <p:outputLabel value="Numero: " id="lblNumero" for="txtNumero" />
                <p:inputText value="#{enderecoBean.endereco.numero}" id="txtNumero"
                    required="true"
                    requiredMessage="É necessário preencher o campo Número!" />
            </h:panelGrid>

            <h:panelGrid columns="4">
                <p:outputLabel value="Bairro: " id="lblBairro" for="txtBairro" />
                <p:inputText value="#{enderecoBean.endereco.bairro}" id="txtBairro"
                    required="true"
                    requiredMessage="É necessário preencher o campo Bairro!" />

                <p:outputLabel value="Complemento: " id="lblComplemento"
                    for="txtComplemento" />
                <p:inputText value="#{enderecoBean.endereco.complemento}"
                    id="txtComplemento" />
            </h:panelGrid>

            <h:panelGrid columns="2">
                <p:outputLabel value="Cep " id="lblCep" for="txtCep" />
                <p:inputText value="#{enderecoBean.endereco.cep}" id="txtCep"
                    required="true"
                    requiredMessage="É necessário preencher o campo Cep!" />
            </h:panelGrid>

            <h:panelGrid columns="4">
                <p:outputLabel value="Estado: " id="lblEstado" for="estado" />
                <p:selectOneMenu id="estado" value="#{enderecoBean.estadoEscolhido}"
                    converter="estadoConverter" required="true">
                    <f:selectItem itemLabel="Selecione" />
                    <f:selectItems value="#{enderecoBean.listaEstados}" var="e"
                        itemValue="#{e}" itemLabel="#{e.sigla}" />
                    <f:ajax render="cidade" event="change"
                        listener="#{enderecoBean.alterarCidadesPorEstado}" />
                </p:selectOneMenu>

                <p:outputLabel value="Cidade: " for="cidade" id="lblCidade" />
                <p:selectOneMenu id="cidade" value="#{enderecoBean.cidadeEscolhida}"
                    converter="cidadeConverter" required="true">
                    <f:selectItem itemLabel="Selecione" />
                    <f:selectItems value="#{enderecoBean.listaCidades}" var="c"
                        itemValue="#{c}" itemLabel="#{c.nomeCidade}" />
                </p:selectOneMenu>
            </h:panelGrid>
        </h:panelGrid>
    </p:fieldset>
</f:view>

EnderecoBean.java

package br.com.biblioteca.bean;

import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import br.com.biblioteca.dao.CidadeDAO;
import br.com.biblioteca.dao.EstadoDAO;
import br.com.biblioteca.model.Cidade;
import br.com.biblioteca.model.Endereco;
import br.com.biblioteca.model.Estado;

@ManagedBean
@ViewScoped
public class EnderecoBean {

    private Endereco endereco;
    private Estado estadoEscolhido;
    private Cidade cidadeEscolhida;
    private List<Estado> listaEstados;
    private List<Cidade> listaCidades;
    private CidadeDAO cidadeDao;

    public EnderecoBean(){
        this.endereco = new Endereco();
        cidadeDao = new CidadeDAO();
        EstadoDAO dao = new EstadoDAO();
        listaEstados = dao.listar();
    }

    public void setEndereco(Endereco endereco){
        this.endereco = endereco;
    }

    public Endereco getEndereco(){
        return this.endereco;
    }

    public Estado getEstadoEscolhido() {
        return estadoEscolhido;
    }

    public void setEstadoEscolhido(Estado estadoEscolhido) {
        this.estadoEscolhido = estadoEscolhido;
    }

    public Cidade getCidadeEscolhida() {
        return cidadeEscolhida;
    }

    public void setCidadeEscolhida(Cidade cidadeEscolhida) {
        this.cidadeEscolhida = cidadeEscolhida;
    }

    public List<Estado> getListaEstados() {
        return listaEstados;
    }

    public void setListaEstados(List<Estado> listaEstados) {
        this.listaEstados = listaEstados;
    }

    public List<Cidade> getListaCidades() {
        return listaCidades;
    }

    public void setListaCidades(List<Cidade> listaCidades) {
        this.listaCidades = listaCidades;
    }


    public void alterarCidadesPorEstado(final AjaxBehaviorEvent event){
        if(estadoEscolhido == null)
            return;     

        try{
            this.listaCidades = cidadeDao.cidadeByEstado(estadoEscolhido);
        }catch(Exception e){
            e.printStackTrace();
            FacesMessage msgErro = new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERRO","Falha ao buscar as cidades atreladas ao estado selecionado!");
            FacesContext.getCurrentInstance().addMessage(null, msgErro);
        }
    }
}

StatusConverter.java

package br.com.biblioteca.converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

import br.com.biblioteca.dao.EstadoDAO;
import br.com.biblioteca.model.Estado;

@FacesConverter(value="estadoConverter")
public class EstadoConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if(value != null || !value.isEmpty()){
            EstadoDAO estadoDao = new EstadoDAO();
            Estado estado = estadoDao.buscar(Integer.valueOf(value));
            return estado;
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if(value instanceof Estado){
            Estado estado = (Estado)value;
            return String.valueOf(estado.getIdEstado());
        }
        return "";
    }

}

CityConverter.java

package br.com.biblioteca.converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

import br.com.biblioteca.dao.CidadeDAO;
import br.com.biblioteca.model.Cidade;

@FacesConverter(value = "cidadeConverter")
public class CidadeConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value != null && !value.equals("")) {
            CidadeDAO dao = new CidadeDAO();
            return dao.buscar(Integer.valueOf(value));
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value instanceof Cidade) {
            Cidade municipio = (Cidade) value;
            return String.valueOf(municipio.getIdCidade());
        }
        return "";
    }

}

Any ideas?

    
asked by anonymous 04.04.2017 / 03:13

1 answer

1

This is a bug in Primefaces that can be easily fixed by placing an element that involves the component that will be updated. Here is a generic example:

<p:selectOneMenu>
    <p:ajax update="panel-pai" />
</p:selectOneMenu>

<h:panelGroup id="panel-pai">
    <p:selectOneMenu id="listaSelecao" />
</h:panelGroup>

If you are using a list that depends on another, do not forget to update the element itself:

<h:panelGroup id="panel-cidade">
    <p:selectOneMenu id="cidade">
        <p:ajax update="panel-cidade panel-estado" />
    </p:selectOneMenu>
</h:panelGroup>

<h:panelGroup id="panel-estado">
    <p:selectOneMenu id="estado" />
</h:panelGroup>

Or put both components inside only one parent element:

<h:panelGroup id="panel-endereco">
    <p:selectOneMenu id="cidade">
        <p:ajax update="panel-endereco" />
    </p:selectOneMenu>

    <p:selectOneMenu id="estado" />
</h:panelGroup>

For you to do this update you should:

  • Send to your managedBean the state selection
  • Through the selected state update the list of Cities
  • Update elements involving selectOneMenus matching

Applied to your code:

<p:panelGrid id="panel-pai" columns="4">
    <p:outputLabel value="Estado: " id="lblEstado" for="estado" />
    <p:selectOneMenu id="estado" value="#{enderecoBean.estadoEscolhido}"
       converter="estadoConverter" required="true">
        <f:selectItem itemLabel="Selecione" />
        <f:selectItems value="#{enderecoBean.listaEstados}" var="e"
                       itemValue="#{e}" itemLabel="#{e.sigla}" />
        <p:ajax update="panel-pai" event="change"
           listener="#{enderecoBean.alterarCidadesPorEstado}" />
    </p:selectOneMenu>

    <p:outputLabel value="Cidade: " for="cidade" id="lblCidade" />
    <p:selectOneMenu id="cidade" value="#{enderecoBean.cidadeEscolhida}"
       converter="cidadeConverter" required="true">
        <f:selectItem itemLabel="Selecione" />
        <f:selectItems value="#{enderecoBean.listaCidades}" var="c"
           itemValue="#{c}" itemLabel="#{c.nomeCidade}" />
    </p:selectOneMenu>
</p:panelGrid>
  • A id was set to the panelGrid that involves its selectOneMenus
  • Your update should be on top of this id that includes selectOneMenus always
  • I recommend switching% from% to% with%
  • Your <f:ajax render="panelX"/> can change <p:ajax update="panelX"/> native to Primefaces if you prefer

I recommend using as many of the native Primefaces tags as you want to mix with the JSTL tags.

One more note, your managedBean should be serialized. Example:

public class EnderecoBean implements Serializable {
    private static final long serialVersionUID = 1L;
}
    
04.04.2017 / 03:35