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…
<select id="cidadesSelect" name="cliente.cidade.id">
<option>Selecione</option>
<c:forEach items="${cidades}" var="cidade">
<option value="${cidade.id}"
><c:if test="${cliente.cidade.id == cidade.id}"> selected="true" </c:if>
>${cidade.nome}</option>
</c:forEach>
</select>
Barbaridade, resolvi um e encontrei outro problema, 
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 -> 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<Cliente> lista() {
return clienteRepository.findAll();
}
@Get("/carregaCidades/")
public void carregaCidades(Long estado) {
List<Cidade> 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 . 
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.