[RESOLVIDO] vRaptor + Combo Box de Cidades

Pessoal, implementei um combo dinâmico de estados,cidades com vraptor transformando em JSON, com base nesse post: http://www.guj.com.br/java/298900-resolvidocombo-estadocidade-vraptor.

Basicamente ele seleciona um estado e conforme o id selecionado ele carrega as cidades.
Porém agora me surgiu um problema, uso o mesmo formulário para inserir e editar, e ao editar ele não carrega automaticamente as informações do combo.

Como proceder nesse caso?

[code]
$(document).ready(function()
{
$(’#estadosSelect’).on(‘change’, function()
{
var selecionado = $(this).val();

   	  	$.ajax({    
       		url:'${pageContext.request.contextPath}/cliente/carregaCidades/',//+ selecionado,    
            data:{estado:selecionado}, // Passa a variável ao server. O nome do parâmetro tem que ser estado, pois foi o nome colocado aqui.    
            dataType:'json', // O Server vai retornar um JSON    
            success:function(data){    
            
            // Precisa transformar de json para objeto html       
            var options = [];  
            options.push(' <option value="0">Selecione</option> '); 
            for (var i = 0; i < data.length; i++) {    
            	options.push('<option value="'+data[i].id+'">'+data[i].nome+'</option>');    
            }    
                   
            $('#cidadesSelect').html(options.join(''));    
           	}
         });   
   	  	
       });    
    });   [/code]

Nesse caso, você vai precisar carregar o estado selecionado e todas as cidades desse estado e selecionar a cidade certa…

Ou seja, na action, você vai precisar saber que é edição e carregar a primeira lista de cidades…

Opa Rafael, seria algo como o evento “onLoad” no “<select>” ??

Não…

Quando vc executa a action, você tem o result para poder incluir variáveis e coisas assim. Use o result para incluir a lista de cidades do estado selecionado (você sabe qual é, pela instancia do objeto que vai ser alterado)…

Ai, no JSP, você faz um c:forEach e popula o combo de cidades… selecionando a cidade que está na instancia do objeto que vai ser alterado…

Rafael, obrigado pela ajuda.
Consegui como descreveu, o mais importante era o “selected” que estava esquecendo.

Segue como ficou… &lt;select id="cidadesSelect" name="cliente.cidade.id"&gt; &lt;option&gt;Selecione&lt;/option&gt; &lt;c:forEach items="${cidades}" var="cidade"&gt; &lt;option value="${cidade.id}" &gt;&lt;c:if test="${cliente.cidade.id == cidade.id}"&gt; selected="true" &lt;/c:if&gt; &gt;${cidade.nome}&lt;/option&gt; &lt;/c:forEach&gt; &lt;/select&gt;

Barbaridade, resolvi um e encontrei outro problema, :frowning:

Agora ao salvar o cadastro e não seleciona nenhuma cidade (não obrigatória) dispara essa exception.

Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: br.com.vraptor.model.Cliente.cidade -&gt; br.com.vraptor.model.Cidade at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:177)

Selecionando a cidade funciona perfeitamente. Alguma idéia?

Mostre os seus modelos de Estado e Cidade.

Mostre também o lugar aonde você faz o save…

Vamos lá.

Controller.

@Resource
@Path("/cliente")
public class ClienteController {

	private final Result result;

	@Autowired
	public ClienteRepository clienteRepository;
	@Autowired
	public EstadoRepository estadoRepository;
	@Autowired
	public CidadeRepository cidadeRepository;
	
	public ClienteController(Result result) {
		this.result = result;
	}

	@Path("/")
	public void index() {
		result.redirectTo(this).lista();
	}

	@Path("/list")
	public List&lt;Cliente&gt; lista() {
		return clienteRepository.findAll();
	}

	
	@Get("/carregaCidades/")
	public void carregaCidades(Long estado) {    
	      List&lt;Cidade&gt; cidades = cidadeRepository.findByEstado(estado);
		  result.use(Results.json()).withoutRoot().from(cidades).serialize(); // Transforma a lista em JSON   
	}  

	@Post("/salvar")
	public void salvar(Cliente cliente) {
		clienteRepository.save(cliente);
		result.redirectTo(ClienteController.class).lista();
	}

Model

@Entity
public class Cliente implements Serializable{

	private static final long serialVersionUID = 6497131244795811390L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String nome;
	private String rg;
	private String cpf;
	private String cep;
	private String endereco;
	private String numero;
	private String complemento;
	private String bairro;

       @ManyToOne
       @JoinColumn(name="cidade_id",nullable=true)
	private Cidade cidade;
Entity
public class Cidade implements Serializable{

	private static final long serialVersionUID = -4980536458589435354L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String nome;
	
       @ManyToOne
       @JoinColumn(name="estado_id")
	private Estado estado;

Enxuguei os get e seters.

[quote=Rafael Guerreiro]Mostre os seus modelos de Estado e Cidade.

Mostre também o lugar aonde você faz o save…[/quote]

Rafael, alguma idéia?

vamos lá, a opção sem valor do select name=“cliente.cidade.id” deveria ter value="":

<select id="cidadesSelect" name="cliente.cidade.id">      
  <option value="">Selecione</option>

se vc selecionar essa opção vazia, quando isso vai para o servidor, o vraptor vai criar uma cidade sem o id setado, por isso o erro do transient.

um fix é fazer algo do tipo:

if (cliente.getCidade() != null && cliente.getCidade().getId() == nul) {
   cliente.setCidade(null);
}

Se isso acontecer muito, dá pra criar um interceptor que resolve isso.

[quote=Lucas Cavalcanti]vamos lá, a opção sem valor do select name=“cliente.cidade.id” deveria ter value="":

<select id="cidadesSelect" name="cliente.cidade.id">      
  <option value="">Selecione</option>

se vc selecionar essa opção vazia, quando isso vai para o servidor, o vraptor vai criar uma cidade sem o id setado, por isso o erro do transient.

um fix é fazer algo do tipo:

if (cliente.getCidade() != null && cliente.getCidade().getId() == nul) {
   cliente.setCidade(null);
}

Se isso acontecer muito, dá pra criar um interceptor que resolve isso.[/quote]

Grande lucas, funcionou perfeitamente… Te devo mais uma . :slight_smile:

Poderia me dar um exemplo do interceptor pra essa situação?

eh um filter que remove parametros que sao id e estao em branco

Show de bola, valeu pela força @Lucas e pro @Rafael tmb.

Status Resolvido.