VRaptor + AutoComplete

Galera, no formulário abaixo estou usando o autocomplete no input de produto. O autocomplete funciona perfeitamente. O meu problema é no momento de salvar, não estou conseguindo submeter o id do produto selecionado no autocomplete. Apenas submete o nome do produto.

Segue abaixo o código do jsp:

<form action="${linkTo[VendaController].salvar}" method="post" class="ajaxForm">
	
	
	<fieldset>
		<legend>Vendas</legend>
		<br/>
		&lt;div style="float: left; width: 100%;"&gt;
			<p>
				&lt;input type="hidden" name="venda.id" value="${venda.id}" /&gt;
				&lt;input type="hidden" name="venda.reserva.id" value="${venda.reserva.id}" /&gt;
				&lt;input id="idProduto" type="hidden" name="venda.produto.id" value="${venda.produto.id}" /&gt;
				&lt;label for="txtNome"&gt;Acomodação&lt;/label&gt;
				&lt;input type="text" id="txtNome" name="venda.acomodacao.numero" value="${venda.acomodacao.numero}" maxlength="255" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Produto:&lt;/label&gt;
				&lt;input type="text" id="txtProduto" name="venda.produto.nome" value="${venda.produto.nome}" maxlength="255" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Desconto:&lt;/label&gt;
				&lt;input type="text" id="txtDesconto" name="venda.desconto" value="${venda.desconto}" maxlength="255" class="input_text"  /&gt;
			</p>	
			
			<p>
				&lt;label for="txtObs"&gt;Quantidade:&lt;/label&gt;
				&lt;input type="text" id="txtQuantidade" name="venda.quantidade" value="${venda.quantidade}" maxlength="255" class="input_text"  /&gt;
			</p>						
		&lt;/div&gt;
		
		&lt;div class="divButtons"&gt;
			&lt;r:buttons delBtn="${not empty venda.id}" msgs="true"/&gt;
		&lt;/div&gt;
		
	&lt;/fieldset&gt;
&lt;/form&gt;

&lt;script type="text/javascript"&gt;

$("#txtProduto").autocomplete('&lt;c:url value="/cadastros/venda/autocomplete.json"/&gt;', {
	
	dataType: "json", // pra falar que vamos tratar um json
	parse: function(produtos) { // para tratar o json 
		// a função map vai iterar por toda a lista,
		// e transformar os dados usando a função passada
		return $.map(produtos, function(produto) {
			return {
			data: produto, // todos os dados do produto
			value: produto.id, // o valor lógico do produto
			result: produto.nome // o que vai aparecer ao selecionar
			};
		});
	},
	formatItem: function(produto) { // o que vai aparecer na lista de autocomplete
	return produto.nome + "(" + produto.valorUnitario + ")";
		}
	});
&lt;/script&gt;

Código do método salvar no meu controller:

	@Transaction
	@Post("/venda/")
	public void salvar(Venda venda){
		venda.setEmpresaId(userInfo.getEmpresa().getId());
		
		validator.validate(venda);  
		 
		validator.onErrorRedirectTo(this).index();
		
		vendas.saveOrUpdate(venda);
		
		result.include(SUCCESS, SUCESS_MSG);
		result.redirectTo(this).index();
	}

O id do produto sempre está null no momento de salvar: venda.produto.id;

Pelo que entendi, nesse código você apenas seta o valor no input txtProduto.
Faltou pegar o retorno produto.id e setar no seu field idProduto.
Algo +/- assim:

$('#idProduto').val(produto.id);

[]'s
Daniel

tem uma option que vc passa pro autocomplete que é uma função select, que vc recebe o dado selecionado e consegue preencher o id, por exemplo:

 select: function(event, ui) {
                        $('#idProduto').val(ui.item.id); 
                },

Fiz a sequinte alteração no código:

&lt;script type="text/javascript"&gt;

$("#txtProduto").autocomplete('&lt;c:url value="/cadastros/venda/autocomplete.json"/&gt;', {
	
	dataType: "json", // pra falar que vamos tratar um json
	parse: function(produtos) { // para tratar o json 
		// a função map vai iterar por toda a lista,
		// e transformar os dados usando a função passada
		return $.map(produtos, function(produto) {
			return {
			data: produto, // todos os dados do produto
			value: produto.id, // o valor lógico do produto
			result: produto.nome // o que vai aparecer ao selecionar
			};
		});
	},
	formatItem: function(produto) { // o que vai aparecer na lista de autocomplete
	return produto.nome + "(" + produto.valorUnitario + ")";
		},
	
	select: function(event, ui) {
		alert("id: " + ui.item.id);
         $('#idProduto').val(ui.item.id); 
 	}
	});
&lt;/script&gt;

O alerta que está dentro do option select nunca é chamado, ou seja, nnca é atribuído o id.

Também tentei usar a solução abaixo, porém funciona só a primeira vez, ao alterar o produto, o id segue sendo o anterior:

	formatItem: function(produto) { // o que vai aparecer na lista de autocomplete
    $('#idProduto').val(produto.id);  
	return produto.nome + "(" + produto.valorUnitario + ")";
		},

vc está usando esse autocomplete? http://jqueryui.com/demos/autocomplete/

Estou usando o autocomplete que é explicado na apostila FJ28.

tente atualizar para a versão do site que eu passei, que tem o callback de select

Ao alterar o plugin o código parou de funcionar. Então estou tentando alterar o código. Estou usando o exemplo “Remote JSONP datasource”, porém está dando erro no path que estou passando na url. Segue o código abaixo:


&lt;script&gt;
	$(function() {

		$( "#txtProduto" ).autocomplete({
			source: function( request, response ) {
				$.ajax({
					url: ('&lt;c:url value="/cadastros/venda/autocomplete.json"/&gt;', //Está dando erro nessa linha. Acho que não reconhece o &lt;c:url....
					dataType: "jsonp",
					data: {
						featureClass: "P",
						style: "full",
						maxRows: 12,
						name_startsWith: request.term
					},
					success: function( data ) {
						response( $.map( data, function( item ) {
							return {
								label: item.nome,
								value: item.nome
							}
						}));
					}
				});
			},
			minLength: 2,
			select: function( event, ui ) {
				log( ui.item ?
					"Selected: " + ui.item.nome :
					"Nothing selected, input was " + this.value);
			},
			open: function() {
				$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
			},
			close: function() {
				$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
			}
		});
	});
	&gt;&lt;/script&gt;

Segue em anexo as imagens.




na url: vc abriu um parêntesis e não fechou

Foi mal! Tentei usar a url com e sem “( )” e, em ambos casos, dá o seguinte erro no console:

self.element.propAttr is not a function
if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) {
jquery...lete.js (linha 51)


bom, primeiro troque o jsonp por só json… e não precisa mandar o print do console :wink:

Blz! Alterado para “json”. Segue o mesmo erro, nem chega chamar o método no controller.

O código ficou:

	&lt;script&gt;
	$(function() {

		$( "#txtProduto" ).autocomplete({
			source: function( request, response ) {
				$.ajax({
					url: "&lt;c:url value='/cadastros/venda/autocomplete.json'/&gt;",
					dataType: "json",
					data: {
						featureClass: "P",
						style: "full",
						maxRows: 12,
						name_startsWith: request.term
					},
					success: function( data ) {
						response( $.map( data, function( item ) {
							return {
								label: item.nome,
								value: item.nome
							}
						}));
					}
				});
			},
			minLength: 2,
			select: function( event, ui ) {
				log( ui.item ?
					"Selected: " + ui.item.nome :
					"Nothing selected, input was " + this.value);
			},
			open: function() {
				$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
			},
			close: function() {
				$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
			}
		});
	});
	&lt;/script&gt;

vc colocou o js do autocomplete novo e tirou o autocomplete antigo?

qual versão do jQuery? se eu não me engano o autocompleteUI precisa de jquery 1.5.x

Sim, removi o antigo e importei o novo. Estou usando esse jQuery:

&lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"/&gt;&lt;/script&gt; &lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"/&gt;&lt;/script&gt; &lt;script type="text/javascript" src="${pageContext.request.contextPath}/javascripts/jquery.ui.autocomplete.js"/&gt;&lt;/script&gt;

http://jqueryui.com/download

tenta baixar de novo, selecionando só o autocomplete… estranho estar acontecendo isso… o $( “#txtProduto” ) existe mesmo?

Fiz novamente o download, substituí o arquivo do plugin. Segue o mesmo erro.

O código do jsp:

&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;


&lt;form action="${linkTo[VendaController].salvar}" method="post" class="ajaxForm"&gt;
	
	
	&lt;fieldset&gt;
		&lt;legend&gt;Vendas&lt;/legend&gt;
		<br/>
		&lt;div style="float: left; width: 100%;"&gt;
			<p>
				&lt;input type="hidden" name="venda.id" value="${venda.id}" /&gt;
				&lt;input type="hidden" name="venda.reserva.id" value="${venda.reserva.id}" /&gt;
				&lt;input id="idProduto" type="hidden" name="venda.produto.id" value="${venda.produto.id}" /&gt;
				&lt;label for="txtNome"&gt;Acomodação&lt;/label&gt;
				&lt;input type="text" id="txtNome" name="venda.acomodacao.numero" value="${venda.acomodacao.numero}" maxlength="255" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Produto:&lt;/label&gt;
				&lt;input type="text" id="txtProduto" name="venda.produto.nome" value="${venda.produto.nome}" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Desconto:&lt;/label&gt;
				&lt;input type="text" id="txtDesconto" name="venda.desconto" value="${venda.desconto}" maxlength="255" class="input_text"  /&gt;
			</p>	
			
			<p>
				&lt;label for="txtObs"&gt;Quantidade:&lt;/label&gt;
				&lt;input type="text" id="txtQuantidade" name="venda.quantidade" value="${venda.quantidade}" maxlength="255" class="input_text"  /&gt;
			</p>						
		&lt;/div&gt;
		
		&lt;div class="divButtons"&gt;
			&lt;r:buttons delBtn="${not empty venda.id}" msgs="true"/&gt;
		&lt;/div&gt;
		
	&lt;/fieldset&gt;
&lt;/form&gt;

	&lt;script&gt;
	$(function() {

		$( "#txtProduto" ).autocomplete({
			source: function( request, response ) {
				$.ajax({
					url: "&lt;c:url value='/cadastros/venda/autocomplete.json'/&gt;",
					dataType: "json",
					data: {
						featureClass: "P",
						style: "full",
						maxRows: 12,
						name_startsWith: request.term
					},
					success: function( data ) {
						response( $.map( data, function( item ) {
							return {
								label: item.nome,
								value: item.nome
							}
						}));
					}
				});
			},
			minLength: 2,
			select: function( event, ui ) {
				log( ui.item ?
					"Selected: " + ui.item.nome :
					"Nothing selected, input was " + this.value);
			},
			open: function() {
				$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
			},
			close: function() {
				$( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
			}
		});
	});
	&lt;/script&gt;

tenta tirar as options do autocomplete (deixa só a source por enquanto) e ve se ainda dá o erro… daí vai colocando uma por uma pra ver aonde tá o erro

Deixei apenas o source, e ocorre o mesmo erro:


	&lt;script&gt;
	$(function() {

		$( "#txtProduto" ).autocomplete({
			source: function( request, response ) {
				$.ajax({
					url: "&lt;c:url value='/cadastros/venda/autocomplete.json'/&gt;",
					dataType: "json",
					data: {
						featureClass: "P",
						style: "full",
						maxRows: 12,
						name_startsWith: request.term
					},
					success: function( data ) {
						response( $.map( data, function( item ) {
							return {
								label: item.nome,
								value: item.nome
							}
						}));
					}
				});
			}

		});
	});
	&lt;/script&gt;

tenta usar o exemplo básico do site, aquele que já tem uma lista pre-estabelecida…

Até no exemplo básico, conforme o código abaixo, segue dando o mesmo erro:

&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%&gt;
&lt;form action="${linkTo[VendaController].salvar}" method="post" class="ajaxForm"&gt;
	&lt;fieldset&gt;
		&lt;legend&gt;Vendas&lt;/legend&gt;
		<br/>
		&lt;div style="float: left; width: 100%;"&gt;
			<p>
				&lt;input type="hidden" name="venda.id" value="${venda.id}" /&gt;
				&lt;input type="hidden" name="venda.reserva.id" value="${venda.reserva.id}" /&gt;
				&lt;input id="idProduto" type="hidden" name="venda.produto.id" value="${venda.produto.id}" /&gt;
				&lt;label for="txtNome"&gt;Acomodação&lt;/label&gt;
				&lt;input type="text" id="txtNome" name="venda.acomodacao.numero" value="${venda.acomodacao.numero}" maxlength="255" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Produto:&lt;/label&gt;
				&lt;input type="text" id="txtProduto" name="venda.produto.nome" value="${venda.produto.nome}" class="input_text" required="required" /&gt;
			</p>
			
			<p>
				&lt;label for="txtObs"&gt;Desconto:&lt;/label&gt;
				&lt;input type="text" id="txtDesconto" name="venda.desconto" value="${venda.desconto}" maxlength="255" class="input_text"  /&gt;
			</p>	
			
			<p>
				&lt;label for="txtObs"&gt;Quantidade:&lt;/label&gt;
				&lt;input type="text" id="txtQuantidade" name="venda.quantidade" value="${venda.quantidade}" maxlength="255" class="input_text"  /&gt;
			</p>						
		&lt;/div&gt;
		
		&lt;div class="divButtons"&gt;
			&lt;r:buttons delBtn="${not empty venda.id}" msgs="true"/&gt;
		&lt;/div&gt;
		
	&lt;/fieldset&gt;
&lt;/form&gt;
	&lt;script&gt;
	$(function() {
		var availableTags = [
			"ActionScript",
			"AppleScript",
			"Asp",
			"BASIC",
			"C",
			"C++",
			"Clojure",
			"COBOL",
			"ColdFusion",
			"Erlang",
			"Fortran",
			"Groovy",
			"Haskell",
			"Java",
			"JavaScript",
			"Lisp",
			"Perl",
			"PHP",
			"Python",
			"Ruby",
			"Scala",
			"Scheme"
		];
		$( "#txtProduto" ).autocomplete({
			source: availableTags
		});
	});
	&lt;/script&gt;