[Resolvido] Checkbox dinâmico com Javascript e VRaptor 3

61 respostas
Guevara

Oi pessoal!
Tenho uma galeria de fotos com 10 fotos, em cada uma existe um checkbox para marcar se é “avatar”, só pode haver uma foto como avatar. Ao subir uma foto marcando um checkbox Avatar a foto é salva no banco com um campo boolean “avatar”. Consigo carregar esse dado da seguinte forma:

<c:forEach var="foto" items="${fotos}">
<c:choose>
		<c:when test="${foto.avatar == true}">
			<input type="checkbox" name="foto.avatar" id="avatar" checked />Avatar
		</c:when>
	<c:otherwise>
			<input type="checkbox" name="foto.avatar" id="avatar" onclick="setAvatar();">Avatar 	
	</c:otherwise>
	</c:choose> 
	   	    
    </c:forEach>

O meu problema está sendo em ao clicar numa outra foto, teria que desmarcar o checkbox da anterior e enviar a id da nova foto por parâmetro e assim atualizar o avatar. Fiz o seguinte:

<script>
function setAvatar() {
	var boxes = document.getElementByName("foto.avatar");
	var foto = document.getElementByName("foto.avatar").value;
	 for(i=0;i<boxes.length;i++) {
			
	      if(boxes[i].checked) {
			boxes.checked=false;
			new Ajax.Request('atualizaAvatar',{
			            method: 'post',
			            parameters: foto,
			            onComplete: function(){
			    			alert('O avatar foi alterado com sucesso!');
			    			
			  			}						            
			        	}
			        );
			    } 					
							
	      }
}
</script>

Pesquisando no Google achei o Prototype: http://www.prototypejs.org/learn/introduction-to-ajax
Estou seguindo o manual dele com outras dicas da internet, mas não está dando certo, ao marcar outra foto a anterior não é desmarcada e tb não passa nada por parâmetro pro Controller:

public void atualizaAvatar(Foto foto) {
		fotoDAO.atualiza(foto);
	}

Na DAO está:

public void atualiza(Foto foto) {
		Transaction tx = session.beginTransaction();
		session.update(foto);
		tx.commit();
	}

Alguém consegue dar alguma dica de como resolver? =)
Abraço!!

61 Respostas

G

Quando você possui apenas UMA opção o correto é usar RADIO. Checkbox é apenas quando você pode ter mais de uma opção.

Lucas_Cavalcanti

e pro parameters vc tem que colocar algo do tipo:

{ 'foto.avatar' : foto }

ou

'foto.avatar=' + foto

recomendo vc usar o JQuery… acho mais fácil que o prototype:

http://api.jquery.com/jQuery.ajax/

G

Eu só não entendi porque usar uma gambiarra dessas de usar javascript ao invés de usar o elemento correto. Não assassinem o HTML, por favor :lol:

Guevara

Obrigado pelas dicas!
Fiz as mudanças, está com radio button, código até agora está assim:

<script>
function setAvatar() {
	var foto = document.elementByName="foto.avatar";
	if (foto.checked=true) {
		
		$.ajax({
		      url: "atualizaAvatar",
		      global: false,
		      type: "POST",
		      data: ({'foto.avatar' : foto}),
		      async:false,
		      success: function(){
		         alert('Avatar alterado com sucesso!');
		      }
		   }
		).responseText;
			
	}		
}
</script>

A DAO ficou desta forma, mas ainda tô raciocinando em cima do método:

public void atualiza(Foto foto) {
		Transaction tx = session.beginTransaction();
		if(foto.getAvatar() == true) {			
		Criteria c  = session.createCriteria(Foto.class);
		Foto fot = (Foto) c.add(Restrictions.eq("idFoto", foto.getIdFoto()))
		.add(Restrictions.eq("avatar", true)).uniqueResult();		
		fot.setAvatar(false);  
		session.merge(fot); 
		tx.commit();
		} else {
		Criteria c  = session.createCriteria(Foto.class);
		Foto fot = (Foto) c.add(Restrictions.eq("idFoto", foto.getIdFoto()));
		fot.setAvatar(true);  
		session.merge(fot);			
		tx.commit();
		}
	}

Tb acho que está bem complicada essa tática, sugerem uma outra forma de setar um avatar para um imóvel sem ser desse jeito?
Abraço!

obs: o GUJ bugou, tá sem o botão de “Responder”, eu respondi na opção “resposta rápida” e depois editei o post.

G

Eu não sei como está sua entidade, mas eu faria diferente. Você tem N fotos, e uma delas será o avatar, correto?

Penso que ao invés da foto ter uma propriedade que diz se ela é avatar ou não, o correto é o Imovel saber quem é o avatar dele. Ou seja, mudando a entidade:

public class Imovel { private List<Foto> fotos; private Foto avatar; }

Guevara

Opa! Valeu Garcia!
Se eu entendi direito, ao fazer upload de uma foto e clicasse no checkbox para marcá-la como avatar o atributo avatar na classe Imovel guardaria a foto. Mas ai teria que alterar os métodos de upload no Controller e salvar no component né?
Abraço!

G

Não precisa ser exatamente no upload. Você pode fazer o upload normalmente e adicionar as fotos como você estava fazendo. A minha sugestão altera apenas a escolha do avatar, que ao invés de vocẽ colocar um isAvatar=true você indica no imovel qual a foto é um avatar.

Guevara

Entendi a idéia, mas lá na JSP vou ter que continuar usando ajax pra mandar os dados da foto selecionada pro Controller e depois dar um update nos dados?

obs: kd o botão de responder do fórum?

G

Guevara, para mim o botão de responder está aparecendo normalmente. Tente limpar o cache, ou algo assim.

Me tira uma dúvida, você tem um imóvel com uma lista de fotos, certo? E apenas uma dessas fotos pode ser o avatar do imovel, é isso? Na entidade Imovel você tem uma coleção de fotos?

Guevara

Isso mesmo Garcia, assim está a tabela Foto no banco:

Fiz um teste com sql direto no banco só pra testar, rodei dois updates, um para setar com false e outro pra setar com true.

Na classe Imóvel tenho:

@OneToMany(targetEntity=Foto.class, mappedBy = "imovel",orphanRemoval=true)	
	public List<Foto> fotos;

obs: o botão “Responder” voltou. O.o

G

Acho que então fica melhor você remover o atributo avatar da classe Foto. Após isso adicione o atributo avatar do tipo Foto na classe Imovel:

public class Imovel { private List<Foto> fotos; private Foto avatar; }

Quase nada muda nas outras classes. Você continua normalmente adicionando e excluindo fotos. O que muda agora é na hora de você escolher quem é o avatar. Dessa forma nova você tem uma lista de fotos, então você marca qual será o avatar.

public void salvarComoAvatar(Foto avatar, Imovel imovel) { [...] imovel.setAvatar(avatar); [...] }

E no seu JSP:

<c:forEach var="foto" items="${fotos}"> <c:choose> <c:when test="${foto.avatar == true}"> <input type="radio" name="avatar.id" id="avatar" checked="checked" value="${foto.id}" onclick="setAvatar();">Avatar </c:when> <c:otherwise> <input type="radio" name="avatar.id" id="avatar" value="${foto.id}" onclick="setAvatar();">Avatar </c:otherwise> </c:choose> </c:forEach>

O Ajax eu não sei como fica porque conheço pouco o jquery. Você basicamente precisa apenas o valor da foto selecionada e também o id do imóvel. Aliás você nem precisa usar Ajax nisso, você pode fazer por formulário normal fazendo submit para o vraptor.

Guevara

Oi Garcia!
Estou com um probleminha aqui na hora de chamar a aplicação. Fiz a alteração que vc sugeriu:

@OneToMany(targetEntity=Foto.class, mappedBy = "imovel",orphanRemoval=true)	
	public List<Foto> fotos; 
	private Foto avatar;

//getter and setter para avatar

E a stacktrace acusa:

root cause

org.hibernate.MappingException: Could not determine type for: br.com.imobiliaria.bean.Foto, at table: Imovel, for columns: [org.hibernate.mapping.Column(avatar)]
	org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:290)
	org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:274)
	org.hibernate.mapping.Property.isValid(Property.java:217)
	org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:464)
	org.hibernate.mapping.RootClass.validate(RootClass.java:236)
	org.hibernate.cfg.Configuration.validate(Configuration.java:1193)
	org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1378)
	org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
	org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:883)
	org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
	javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
	br.com.caelum.vraptor.util.jpa.EntityManagerFactoryCreator.create(EntityManagerFactoryCreator.java:39)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	java.lang.reflect.Method.invoke(Method.java:597)
	org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:340)
	org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:293)
	org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:130)
	org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:394)

Não está aceitando o atributo do tipo Foto na classe Imovel, precisa anotar algo lá?
Abraço!

softwork

Sim amigo!

Você precisa colocar a anotação @OneToOne, pois segundo a tua necessidade, o imóvel só deverá ter um avatar.

@OneToMany(targetEntity=Foto.class, mappedBy = "imovel",orphanRemoval=true)   
     public List&lt;Foto&gt; fotos;

     @OneToOne
     @Column(name="id_foto")   
     private Foto avatar;  
  
     //getter and setter para avatar

Com isso o Hibernate irá criar um atributo chamado id_foto na tua entidade Imovel.

Guevara

Obrigado softwork.
Vou tentar aqui.

Leandro-SP

Oi pessoal…
Aproveitando o topico… alguém sabe como gero um formulario dinamico com o vraptor3… estava pensando em algo do tipo campos basicos como Nome, Endereço, Data de Nascimento, Sexo, e mais alguns serem fixos, e outros campos serem dinamicos no formulario. Como por exemplo buscar os campos dinamicamente no Mysql e gerar a tela de formulario. Estou querendo a cabeça aqui e não consigo. Apenas queria que facilitasse na hora de incluir mais um campo no formulario era só inserir mais uma linha numa tabela do mysql.
Alguem pode me ajudar?
Aguardo resposta.
Obrigado.
Leandro.

G

Leandro, tem um gerador de código feito por um usuário do Vraptor: http://guj.com.br/posts/list/199727.java

Guevara

Oi pessoal!
Já entendi como fazer pra salvar esse avatar na tabela Imovel, mas estou com dúvidas na hora de implementar isso.
O problema é que apenas um imovel.setAvatar(avatar); no método de upload salva() não funciona, precisaria de um método de salvarAvatar() lá na DAO pra concluir o processo.
Algo do tipo:

public void salvarAvatar(Imovel imovel, Foto avatar) {
		Transaction tx = session.beginTransaction();	
		session.save(objeto); 
                //session.update(imovel); 
		tx.commit();
	}

No método salva() esta assim:

public void salva(UploadedFile imagem, Imovel imovel, Foto foto, Foto avatar ) {
		
                      //codigo de upload

			//ImovelDAO imovelDao = new ImovelDAO();
			imovel.setAvatar(avatar); //este cara sozinho não salva o avatar na tabela imovel
			//imovelDao.salvaAvatar(imovel, avatar);	
		
			//codigo para salvar a foto na tabela Foto	    
		} catch (IOException e) {
			throw new RuntimeException("Erro ao copiar imagem", e);
		}		
	}

Precisaria de um metodo em ImovelDAO para salvar essa foto lá não?
Outra coisa, no meu componente Imagens, que é o código acima, a DAO injetada no construtor da classe não funciona, nem FotoDAO, nem ImovelDAO, preciso instanciar cada um deles no método salva(). O estranho é que é só na classe Imagens, que é um @Component. Preciso anotá-la com @RequestScoped que nem as DAO’s?

Abraço!!

Lucas_Cavalcanti

pra salvar um Imovel vc precisa salvar a Foto ANTES…
ou configurar o Cascade para PERSIST, aí ele faz automático…

qto ao problema dos daos, se a sua classe Imoveis é Session ou ApplicationScoped vc não consegue fazer um DAO, que é RequestScoped, funcionar…
isso pq assim que a Imoveis é criada, um DAO é criado e passado pra ele… mas o dao depende da requisição, então na primeira requisição a session (do hibernate) dele é fechada, e nas próximas ele vai ficar com um DAO inválido…

uma solução:

  • receba uma SessionFactory no construtor do Imoveis, e controle a sua sessão na mão, instanciando os DAOs na mão (mas uma vez só);
    vc pode abrir a sessão já no início da classe (se o Imoveis for application scoped) e controlar as transações manualmente…
Guevara

Oi Lucas!
Obrigado pelas dicas. Tentei seguir a dica do Garcia mas não dá, pq se eu salvo a foto, no imovel não salva nada, pois até então nada em Foto foi gravado. Estou pensando em criar uma classe Avatar só pra isso, ai a url do avatar não será salva na tabela Foto.

public void salva(UploadedFile imagem, Imovel imovel, Foto foto, Foto avatar) {
//outros codigos...
String nome = foto.getNome();
			foto.setNome(nome);
			String caminho = destino.getName();
			foto.setUrlFoto(caminho);
			foto.setImovel(imovel);				
		    fotoDAO.adiciona(foto);	// Foto salva sem problemas
		    imovel.setAvatar(avatar); // objeto null

Tô quebrando a cabeça pra não criar código que cause dados duplicados de fotos no banco. =/
Acha a opção de criar uma classe Avatar especifica para isso uma opção ruim?
Abraço!!

softwork

Amigo, acho melhor você criar uma chamada AJAX para determinar quem é o AVATAR e outro AJAX para salvar/vincular as FOTOS do imóvel.

E o ideal é para cada AJAX ter uma URL específica e seus respectivos parâmetros. Isto facilitará seu entendimento…

Como você mesmo disse: O parâmetro Foto avatar, através da assinatura: public void salva(UploadedFile imagem, Imovel imovel, Foto foto, Foto avatar), esta vindo nulo e isto ocorre no momento em que o vRaptor injeta os valores para os parâmetros e como ele não encontrou, no teu JSP, uma referência correspondente para avatar, ele injeta nulo.

Então para facilitar, você poderá ter uma lógica para salvar a FOTO do imóvel, passando os parâmetros: IMÓVEL e FOTO.

E outra lógica para atribuir um AVATAR para o IMÓVEL, passando os parâmetros: IMÓVEL e AVATAR. Porém neste caso você deverá primeiro localizar o imóvel pelo seu ID em seguida atribuir o avatar ao seu atributo “fazer um setAvatar(avatar)” e ao final salvar o imóvel.

É muito simples!

Eu sinceramente indico a você dar uma estudada na apostila da Caelum: FJ-28: Desenvolvimento ágil para Web 2.0 com VRaptor, Hibernate e AJAX

Nela você encontrará todas esta informações bem detalhadas e só terá que modificá-las conforme a tua necessidade.

Guevara

Tarde pessoal! O/
Meu <c:choose> está maluco, existe somente uma foto que é avatar no banco mas ele marca todas os radio button na jsp.

<c:choose>
	<c:when test="${imovel.avatar != null}">  
	<input type="radio" value="${imovel.avatar}" checked="checked" />Avatar	
	</c:when>	
	<c:otherwise>	 
	<input type="radio" name="avatar" value="${imovel.avatar}" onclick="setAvatar();" />Avatar
	</c:otherwise>
	</c:choose>

Se tenho apenas uma foto como avatar na coluna avatar_id_foto da tabela Imovel, pq ele marca os dois?

Tentei com avatar.id tb, mas nenhum radio button fica marcado.

<c:choose>
	<c:when test="${avatar.id != null}">  
	<input type="radio" value="${avatar.id}" checked="checked" />Avatar	
	</c:when>	
	<c:otherwise>	 
	<input type="radio" name="avatar" value="${avatar.id}" onclick="setAvatar();" />Avatar
	</c:otherwise>
	</c:choose>

Onde eu tô errando?

Valeu!!

Lucas_Cavalcanti

ao invés de ${imovel.avatar != null} faça ${not empty imovel.avatar}

Guevara

Obrigado Lucas, mas não deu boa.
Tentei dessa forma e inclusive com ${not empty avatar.id}, o comportamento é o mesmo, ou preenche td ou fica td vazio, a tabela Imovel possui um imovel com a id da foto na coluna.

Então se a coluna não estiver vazia, deveria dar um checked na foto certa e o resto deixar desmarcado né? Acho que o meu raciocinio está correto…

Abraço!

Lucas_Cavalcanti

bom, acho que o que vc quer testar não é se o avatar existe, e sim se ele é igual à foto atual, não?

seu teste então deveria ser algo do tipo: ${imovel.avatar.id eq foto.id} (e vc tá iterando sobre as fotos)

Leandro-SP

Leandro-SP:
Oi pessoal…
Aproveitando o topico… alguém sabe como gero um formulario dinamico com o vraptor3… estava pensando em algo do tipo campos basicos como Nome, Endereço, Data de Nascimento, Sexo, e mais alguns serem fixos, e outros campos serem dinamicos no formulario. Como por exemplo buscar os campos dinamicamente no Mysql e gerar a tela de formulario. Estou querendo a cabeça aqui e não consigo. Apenas queria que facilitasse na hora de incluir mais um campo no formulario era só inserir mais uma linha numa tabela do mysql.
Alguem pode me ajudar?
Aguardo resposta.
Obrigado.
Leandro.

Alguém pode me ajudar por favor? Acho melhor eu abrir outro topico?

Leandro-SP

Leandro-SP:
Oi pessoal…
Aproveitando o topico… alguém sabe como gero um formulario dinamico com o vraptor3… estava pensando em algo do tipo campos basicos como Nome, Endereço, Data de Nascimento, Sexo, e mais alguns serem fixos, e outros campos serem dinamicos no formulario. Como por exemplo buscar os campos dinamicamente no Mysql e gerar a tela de formulario. Estou querendo a cabeça aqui e não consigo. Apenas queria que facilitasse na hora de incluir mais um campo no formulario era só inserir mais uma linha numa tabela do mysql.
Alguem pode me ajudar?
Aguardo resposta.
Obrigado.
Leandro.

Alguém pode me ajudar por favor? Acho melhor eu abrir outro topico?

Lucas_Cavalcanti

O garcia-jj já tinha te respondido…

Enfim…

se vc quer fazer um formulario de adição (não de edição) dinâmico, vc pode fazer algo do tipo:

result.include("campos", umaListaDeStringComONomeDosCampos);

no jsp:

<c:forEach items="${campos}" var="campo">
    <label for="${campo}"><fmt:message key="${campo}"/></label>
    <input id="${campo}" type="text" name="${campo}"/>
</c:forEach>

de qqer forma, não me parece algo muito fácil de manter ou entender o que tá acontecendo…
vc não tem um jeito melhor de fazer o que vc quer?

Leandro-SP

O garcia-jj já tinha te respondido…

Enfim…

se vc quer fazer um formulario de adição (não de edição) dinâmico, vc pode fazer algo do tipo:

result.include("campos", umaListaDeStringComONomeDosCampos);

no jsp:

<c:forEach items="${campos}" var="campo">
    <label for="${campo}"><fmt:message key="${campo}"/></label>
    <input id="${campo}" type="text" name="${campo}"/>
</c:forEach>

de qqer forma, não me parece algo muito fácil de manter ou entender o que tá acontecendo…
vc não tem um jeito melhor de fazer o que vc quer?

Lucas Cavalcanti,
Não consegui pensar numa forma diferente de fazer isso.
Teria um formulário padrão com campos básicos e também poderia incluir algumas linhas numa tabela do Mysql e cada linha seria o nome de um novo campo novo no formulário. Vou tentar fazer desse jeito que você passou… mas será uma boa idéia essa? A idéia é poder incluir um novo campo num formulario facilmente…sem ter que mapear esse novo campo num DAO.

Ex.:

Nome
Endereço
Sexo
Data Nascimento
Telefone
E-mail

São os campos básicos. Que sempre existirão.

Aí incluiria uma linha numa tabela X com o texto: “Possui Carro?”.
E aí geraria um formulario do tipo:

Nome
Endereço
Sexo
Data Nascimento
Telefone
E-mail
Possui Carro? (aqui ainda teria que dar um jeito de colocar um Checkbox com SIM ou NÃO)

Entendeu?

Aguardo resposta.
Obrigado.
Att,
Leandro.

Lucas_Cavalcanti

cara, até dá pra fazer isso, mas vai dar um trabalho bem grande…

vc vai precisar de uma classe pra representar um campo do formulário, com nome, label e tipo pelo menos
a partir disso vc vai gerar o input/select/textarea/checkbox necessário…

e como vc vai receber esses dados “dinamicos” no seu controller? não parece algo mto fácil nem bom de fazer… seus campos vão mudar tanto assim? tanto a ponto de vc não querer mudar o seu código da aplicação?
vale a pena perder um tempo grande com isso agora?

Guevara

Oi Lucas!
Fiz um teste aqui com javascript para capturar o valor de imovel.avatar, olha o que está vindo:

Não está vindo a id da foto, mas essa string doida ai. Deveria vir a id 258 que esta lá.

Abraço!!!

Lucas_Cavalcanti

se vc quer que venha a id vc precisa colocar:
${imovel.avatar.id}

pq imovel.avatar eh a foto inteira

Guevara

Agora foi! Valeu Lucas!=)

<c:when test="${imovel.avatar.idFoto eq foto.idFoto}">

Beleza, agora já consigo marcar no radio button quem é o avatar, só falta criar a função ajax pra mandar o imovel e foto pro Controller e atualizar no banco quem é o avatar.
Abraço!!

Guevara

Tô tentando testar o Controller mas os dados não estão chegando até ele:

public void teste(Imovel imovel, Foto foto) {
		 result.include("mensagem", "dados recebidos pelo Controller");
	 }
var foto = $('input[name=avatar]:checked').val();
var imovel = "${imovel.idImovel}";

$.ajax({
	   type: "POST",
	   url: "teste",
	   contentType: "application/x-www-form-urlencoded", 
	   async: false, 
	   data: {imovel: 'imovel', foto: 'foto'},
	   success: function(){
	     alert( "Teste do Controller!" );
	   }
	 });

É isso mesmo? Só colocar o método que está no Controller ali na url?
Abraço!!

Lucas_Cavalcanti

no data vc tem que setar os campos do imovel e foto:

data: { 'imovel.id' : 33, 'foto.id' : 25 }
Guevara

Nem sinal de vida Lucas… =/
Alterei o “data”.

<script type="text/javascript">
$(document).ready(function() {
$("input[name*='avatar']").click(function() {
// inicio do codigo ajax

$.ajax({
	   type: "POST",
	   url: "teste",
	   contentType: "application/x-www-form-urlencoded", 
	   async: false, 
	   data: { 'imovel.id' : 33, 'foto.id' : 25 },
	   success: function(){
	     alert( "Teste do Controller!" );
	   }
	 });

// final do codigo ajax	
	});
});
</script>

Segui o manual do ajax lá no site, não consigo ver nada de errado ai.

Lucas_Cavalcanti

existe o método setId(…) nas classes Imovel e Foto?
se não tiver, mude o id para o nome dos seus setters (sem o set e com a primeira minuscula)

Guevara

Na verdade eu só quero testar se o Controller esta recebendo, vou mandar as id’s pro Controller e redirecionar pra jsp os valores.

public void teste(Long idImovel, Long idFoto) {
		 result.include("mensagem", "dados recebidos:" + idImovel + idFoto);
	 }

Tô tentando enviar daquela forma:

$.ajax({
	   type: "POST",
	   url: "teste",
	   contentType: "application/x-www-form-urlencoded", 
	   async: false, 
	   data: { 'imovel.idImovel' : 35, 'foto.idFoto' : 25 },
	   success: function(){
	     alert( "Teste do Controller!" );
	   }
	 });

Na JSP:

<h3>${mensagem}</h3>

Mas não acontece nada. =/
Assim que esse teste funcionar eu eu vou entender como funciona a requisição ajax e depois altero o Controller pra persistir os dados. Mas primeiro a bagaça têm que funcionar. =) A url está certa? É só o método que está no Controller?

Lucas_Cavalcanti

se o nome do parametro é idImovel e ele é de um tipo primitivo (números, strings e datas), vc precisa mandar um parametro na requisição chamado idImovel:

data: { 'idImovel' : 35, 'idFoto' : 25 }

http://vraptor.caelum.com.br/documentacao/resources-rest/

Guevara

Favoritei esse link. =)

O problema é que a função ajax não está funcionando, fiz um teste simples de alerta, sem usar o Controller, pegando apenas o que está na JSP.

var foto = $('input[name=avatar]:checked').val();
var imovel = "${imovel.idImovel}";
alert("O valor do radio button selecionado é: " + foto + " e o imóvel é: " + imovel);

O resultado:

Ou seja, o problema é no ajax:

$.ajax({
	   type: "POST",
	   url: "teste",
	   contentType: "application/x-www-form-urlencoded", 
	   async: false, 
	   data: { 'idImovel' : 35, 'idFoto' : 25 },
	   success: function(){
	     alert( "Teste do Controller!" );
	   }
	 });

É isso ai que não tá funcionando, e eu não sei se é a uri, ou outro parâmetro da função. =/

Lucas_Cavalcanti

vc tem o firebug no seu firefox?
se não tiver, instale-o e veja qual url essa função ajax está chamando…

essa url teste talvez esteja errada mesmo…
tenta colocar a url assim:

///teste

Guevara

O Firebug mostra o mesmo que está na jsp, cliquei lá em “script” e vi o conteúdo que aparece naquele console do Firebug.
Tentei de várias formas, /imobiliaria/foto/teste, /foto/teste, http://localhost:8080/imobiliaria/foto/teste, e não deu certo.

Lucas_Cavalcanti

e a requisição, o que ele tah mostrando?

Lucas_Cavalcanti

chama essa url no browser:
http://localhost:8080/imobiliaria/foto/teste

Guevara

Opa!
Veja Lucas, ao chamar essa URL no browser ele redireciona para a página de adicionar fotos:

The requested resource (/imobiliaria/foto/adiciona/) is not available.

Conforme o meu método:

public void teste(Long idImovel, Long idFoto) {
		 result.include("mensagem", "dados recebidos" + idImovel + idFoto);
		 result.use(Results.logic()).redirectTo(FotoController.class).adiciona(idImovel);
	 }

Essa parte está certa, mas o ajax não está funcionando, não manda nada pro Controller, e mesmo se mandar os parâmetros, o Controller vai redirecionar pra página que está no Results.logic no método teste()?
Abraço!!

Lucas_Cavalcanti

sim, mesmo sem mandar os parâmetros deveria cair no seu método…

a uri tá errada…
habilite o log de debug do vraptor e veja o que aparece na inicialização do servidor… ele lista todas as rotas, vê qual delas eh a que cai nesse método

Guevara
13:40:25,781 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for FotoController.teste(Long, Long) as [idImovel, idFoto]
13:40:25,781 DEBUG [DefaultParametersControl] For /foto/teste retrieved /foto/teste with {}
13:40:25,782  INFO [RouteBuilder        ] /foto/teste                                       [ALL] -> FotoController.teste(Long, Long)

Pelo visto têm que ser /foto/teste né?

Guevara

Não deu certo não…=/

<script type="text/javascript">
$(document).ready(function() {
$("input[name*='avatar']").click(function() {
// inicio do codigo ajax
$.ajax({
	   type: "POST",
	   url: "/foto/teste",
	   contentType: "application/x-www-form-urlencoded", 
	   async: false, 
	   data: { 'idImovel' : 35, 'idFoto' : 25 },
	   success: function(){
	     alert( "Teste do Controller!" );
	   }
	 });
// final do ajax	
	});
});

Nada acontece com esse ajax, tá mortinho da silva.

Lucas_Cavalcanti

tenta fazer funcionar digitando a url no browser…

deveria ser //foto/teste

Guevara

Fiz o teste colocando os dados reais diretos na URL:

http://localhost:8080/imobiliaria/foto/teste?idImovel=69&idFoto=259

E funcionou, o Controller enviou os dados pra JSP na boa, o problema mesmo é a função ajax.
Tá osso hehe, pq a minha função é o que existe na documentação.

Lucas_Cavalcanti

troca o $.ajax por:

$.get('/imobiliaria/foto/teste', 
        {idImovel: 69, idFoto: 259},
        function(data) {
            alert(data);
        });

troque o $.get por $.post se vc quiser fazer um post

Guevara

Apareceu uma janela com os dados do site, mas na JSP não apareceram os dados, o Controller não recebeu nada.

Lucas_Cavalcanti

apareceu um alert com um html?

não passou pelo controller?

Guevara

Isso, apareceu um alert do html, mas na JSP não imprimiu as id’s.

Lucas_Cavalcanti

então tah certo…

não apareceu nada no html do browser pq vc não pediu pra fazer isso!

qdo vc executa o javascript $.get vc não está mais no JSP, está no html gerado… não dá pra fazer mais nada do jsp…

o que o alert mostrou vc pode tratar de algum jeito e colocar na tela, mas vc precisa fazer ocódigo pra isso acontecer…

por exemplo, se vc tiver uma

vc pode fazer isso na function dentro do $.get:
function(data) {  
     $('#abc').html(data);
}

daí apareceria na tela

Guevara

Valeu Lucas!
Deu certo, estava faltando isso mesmo, precisava ter algum alvo para injetar os dados:
Enviando:

$.post('/imobiliaria/foto/teste', 
        {idImovel: 69, idFoto: 259},
        function(data) {  
       	$('.result').html(data);
        alert('Dados enviados e recebidos pelo Controller.');

});

Controller recebe os dados e envia para a JSP:

public void teste(Long idImovel, Long idFoto) {
		 result.include("mensagem", "dados recebidos" + idImovel + idFoto);
		 result.use(Results.logic()).redirectTo(FotoController.class).adiciona(idImovel);
	 }

Pegando os dados na JSP:

<h3 class="result">${mensagem}</h3>

Só que o Controller está duplicando a página toda ao responder a requisição. A página adiciona() tá com duas páginas adiciona() em uma JSP. =/

Ele criou dois headers, dois body’s, dois footers, sendo que no primeiro body onde estão os dados os mesmos ficaram em negrito, o segundo body ficou sem os dados enviados para o Controller e normal.

Lucas_Cavalcanti

se vc colocou o include-prelude e include-coda, ele vai fazer isso em toda jsp, inlusive essa que foi chamada via ajax…

o que vc pode fazer é colocar um parâmetro na requisição que pode desabilitar o header e o footer:

header.jspf e footer.jspf:

<c:if test="${empty plain}">
    o header ou o footer
</c:if>

e nessa lógica que é ajax, vc coloca um:

result.include("plain", true);
Guevara

Opa! Tô de volta. 0/
Tô quase lá Lucas, a surra agora é numa variável pra armazenar a id da foto, veja:

22:21:49,259 DEBUG [ParanamerNameProvider] Found parameter names with paranamer for FotoController.atualizaAvatar(Long, Foto) as [idImovel, avatar]
22:21:49,259 DEBUG [ParametersInstantiatorInterceptor] Parameter values for [DefaultResourceMethod: FotoController.atualizaAvatarFotoController.atualizaAvatar(Long, Foto)] are [69, null]

O "avatar tá vindo null, e tô tentando pegar assim:

var avatar = $("input[id*='avatar']").val();
var idImovel = "${imovel.idImovel}"; 

$.post('/imobiliaria/foto/atualizaAvatar', 
        {'idImovel': idImovel, 'avatar': avatar},
        function(data) {  
       	$('.result').load(data);              	
        alert('Avatar selecionado com sucesso!');

});

No Controller está assim:

public void atualizaAvatar(Long idImovel, Foto avatar) { // o avatar aqui chega null
		 Imovel imovel = imovelDAO.carrega(idImovel); 
		 imovel.setAvatar(avatar);
		 imovelDAO.atualiza(imovel); 
		 result.include("mensagem", "Avatar selecionado com sucesso!");
		 result.use(Results.logic()).redirectTo(FotoController.class).adiciona(imovel.getIdImovel());
	}

Deveria ir com a id da foto que está no :

<input type="radio" id="avatar"  value="${foto.idFoto}" />Avatar

A id do imóvel pego tranquilo mas essa id da Foto tá osso, pq na classe Imovel avatar é do tipo Foto e não um Long.
Sabe como pego essa id da foto pra dar um setAvatar() ali no imóvel?
Assim que resolver essa e o parâmetro for passado vou ver se o método load() pode ser usado no lugar do html() do jquery.

$('.result').load(data);

Abraço!!

Lucas_Cavalcanti

se vc passa o parametro avatar=33 o que você espera que o VRaptor faça?
o que é esse 33?

é o id da foto, não é verdade?
se vc quer setar o id da foto, você precisa colocar o caminho do id da foto (navegando pelos getters e setters):

avatar.idFoto=33

se vc quer, por exemplo, setar o id da foto que está dentro do imóvel :

//modificadores de acesso omitidos
class Imovel {
     Long idImovel
     Foto avatar;
     List<Foto> fotos;
     //getters e setters
}
class Foto {
     Long idFoto;
     //getters e setters
}

e no controller:

public void metodo(Imovel bolinha) {

}

bolinha.avatar.idFoto = 33 seta o id da foto
bolinha.idImovel = 222 seta o id do imovel

bolinha.fotos[0].id = 234 seta o id da primeira foto da lista de fotos

Guevara

Creio eu que fiz isso, só a parte do ajax que tá pegando, pq eu coloquei:

{'idImovel': idImovel, 'avatar.idFoto': avatar},

Só que eu clico na foto 260 e salva no banco a foto 258 na tabela imovel, se eu clico no 259 salva 258. Não tô entendendo essa não. O.o

Lucas_Cavalcanti

isso é pq você está selecionando o valor errado no javascript:

var avatar = $("input[id*='avatar']").val();

isso seleciona o valor de um input que começa (ou contêm, não lembro o que o * significa) com avatar.

o que vc queria fazer eh selecionar o valor do radio button que vc acabou de clicar, certo? isso vc faz assim:
-coloque class=“avatar” em todos os radiobuttons do avatar

$("input.avatar").click(function() { //ao clicar no radiobutton
     var avatar = $(this).val(); //valor do input que foi clicado
     //o resto do código
});
Guevara

Deu boa Lucas!!! Valeu pela força! =)
A função ajax() ficou assim:

<script type="text/javascript">
$(document).ready(function() {
$("input.avatar").click(function() {
// inicio do codigo ajax

var avatar = $(this).val();
var idImovel = "${imovel.idImovel}";
$.post('/imobiliaria/foto/atualizaAvatar', 
        {'idImovel': idImovel, 'avatar.idFoto': avatar},        
        function() {  
        window.location.reload(),            	
        alert('Avatar selecionado com sucesso!');
});

// final do ajax	
	});
});
</script>

Envia a id do imovel e a id do avatar, após isso recarrega a janela e em seguida mostra o alerta de sucesso.
Como já têm a janela de alerta, removi a mensagem de sucesso de alteração enviada pelo Controller.
Abraço!!

Criado 25 de julho de 2010
Ultima resposta 6 de ago. de 2010
Respostas 61
Participantes 5