Exibir mais resultados com VRaptor + Ajax

Boa tarde, pessoal.

Estou tentando desenvolver um paginador no mesmo estilo do Twitter para minha aplicação, exibindo os 100 primeiros resultados por vez.
Pesquisei no forum, em sites e não encontrei nenhuma solução que fizesse da forma que preciso.

Então tentei realizar da seguinte forma:

Os parametros que utilizarei para paginar são limit + offset (no banco de dados).

No meu Controller, criei o seguinte método

public List<Pessoa> nome(String nome, Integer cidade, Integer offset) { // este offset SEMPRE será zero, pois se trata do método da primeira busca
	result.include("nome", nome);
	result.include("cidade", cidade);
	return pessoaRepository.buscaNome(nome, cidade, offset);
}

Ou seja, simplesmente entrego para o repository os parametros de nome, cidade e o offset 0. E ele me retorna a lista perfeitamente.

Pensei em incluir os parametros que utilizei anteriormente na página onde seriam exibidos os resultados, pois daí poderia utilizar um form escondido com inputs do tipo “hidden” com os valores que eu preciso para fazer a nova busca, claro que caso se o tamanho da lista mostrada fosse igual a 100. Ou seja, teria de ter um formulario mais ou menos assim:

<form method="post" action="/mais">
 <input type="hidden" name="nome" value="${ cidade }" />
 <input type="hidden" name="cidade" value="${ cidade }" />
 <input type="hidden" name="offset" value="100" />
 <button type="submit">Mais resultados</button>
</form>

inicialmente, o valor do offset seria 100. Javascript poderia cuidar de incrementar esse valor no futuro.

E no meu Controller, seria mais ou menos assim:

@Post @Path("/mais")
public void maisResultados(String uf, String nome, Integer cidade, Integer offset){
	List<Pessoa> pessoaList = pessoaRepository.buscaNome(nome, cidade, offset);
	result.use(Results.json()).from(pessoaList).serialize(); //é assim que se envia para a página a lista?
}

Então vamos para as minhas dúvidas:

A solução que eu utilizei está correta? ela tem brechas para injeção de sql ou algo do tipo?

Como eu faria para aplicar estes resultados na minha página? eu pesquisei e só encontrei soluções em php. Alguém já viu alguma solução dessas para java?
A única que entendi mais ou menos foi essa:

Agora não estou conseguindo adaptá-la para o meu código. Como faria para esse $.ajax({}); jogar as informações na div #conteudo e incrementar o valor do campo offset no formulário do botão “mais”?

Muito obrigado pessoal :wink:

faça algo parecido com:

<form id="mais" method="post" action="/mais">
      ....
     <input type="hidden" id="offset" name="offset" value="100" />  
</form>

e no javascript:

$('#mais').submit(function() {
    $.getJSON($(this).action(), $(this).serialize(), function(json) {
           //itera no json e joga as informações em #conteudo
    });
    $('#offset').val(parseInt($('#offset').val()) + 10);
    return false; //pro form não submeter
});

Opa cara, obrigado aí pela dica.

Fiz exatamente como você me falou, mas mesmo com o return false do javscript, o form está submetendo do mesmo jeito para a url. Como se tentasse achar a página “maisResultados.jsp”.

Será que tem outra forma de se fazer isso?

EDIT: Este erro seria pois estou usando o método com @Post? Estou utilizando post por causa da segurança.

Obrigado.

se vc usa post, vc tem que usar o $.ajax mesmo (ou $.post)

post não te dá segurança, por assim dizer. Qualquer um consegue fazer um post, vc só dificultou um pouquinho, pois eles não vão conseguir fazer direto no browser :wink:

semanticamente vc deveria usar GET mesmo (a menos que vc mude algo no servidor)

de qqer modo, vc pode usar isso pra post:

$.ajax({
    url: $(this).action(),
    data: $(this).serialize(),
    dataType: "json",
    method: "post",
    success: function(data) {
          ...
    }
});

Lucas,

Conforme você sugeriu, troquei o método do formulário para GET mesmo e consegui fazer funcionar :smiley:
O único problema é que não consigo jogar a requisição para a div mesmo (problema de javascript, creio eu).

Ele direciona para o resultado da lista (como se eu acessasse o método DIRETO pela url), ignorando o return false.

Olha o trecho de código que eu estou usando para tentar alimentar a minha div:

[code]$(’#mais’).submit(function() {
$.ajax({
url: $(this).action(),
data: $(this).serialize(),
dataType: “json”,
success: function(data) {
var lista = data.list;
for(var i in lista) {
var pessoa = $(’

’ + lista[i].codigo + ’ - ’ + lista[i].nome + ‘

’);
pessoa.appendTo(’#conteudo’);
}
}
});
$('#offset').val(parseInt($('#offset').val()) + 100);
return false;

});[/code]

Eu sei que é dúvida de javascript, mas tem algo de errado aí? Obrigado!

tá entrando nessa function? espalha uns console.log ou alert aí dentro pra ver se está funcionando.

é possível que tenha um erro na linha 15, daí ele não chega a executar o return false

Cara, tava dando tudo errado, aí resolvi utilizar os parâmetros dentro da url, da seguinte forma:

Arranquei o form, deixei só um Anchor mesmo. E coloquei assim:

$('#mais').click(function(e) {
	$.ajax({
		url: '/mais?offset=100&nome=MARIA&cidade=0',
		dataType: 'json',

E deu tudo muito certo! Obrigado mesmo :smiley:

Mas aí vem a dúvida. Eu posso restringir esta url (método get) para que apenas usuário logados possam ver, utilizando um controle de acesso, certo?

sim, vc pode colocar um interceptor de controle de acesso que passe pela lógica do /mais também.

Eu estou fazendo algo parecido e veio a dúvida: e se eu quisesse utilizar o mesmo método do meu controller para gerar o JSON e o HTML? Digo, a primeira solução foi muito boa, porque se o JS estiver desligado, o form funciona “normal” e você poderia fazer ele redirecionar para os 100 próximos resultados em HTML, e se estiver ligado você dá um “override” no onSubmit() do form e força o pedido por JSON da mesma página.

Minha dúvida é: como, lá no método do meu controller, eu diferencio um pedido do outro? Pra eu poder fazer algo como

if (json){
result.use(Results.representation()).from(meuResultado).serialize();
return;
} //else -> chama o meu_motodo.jsp normalmente

se vc chama:

result.use(representation()).from(meuResultado).serialize();

e o formato for html, ele chama a jsp, incluindo o meuResultado na response

Lá venho com mais uma dúvida.

Minha lista está funcionando perfeitamente. Sendo que quando recebo a lista, preciso verificar se o valor está nulo, para então decidir se exibo ou não o rotulo referente a essa informação. O que faço é o seguinte:

<c:if test="${ cliente.telefone != null }">
   <p><span class="rotulo">Telefone:</span>${ cliente.telefone }</p>
</c:if>

Como pode ver, muito fácil de se fazer com jstl.

Agora como se fazer isso com a lista do json? tenho como manipulá-la de outra forma, ou só pelo Javascript, como estou fazendo neste trecho de código? Que verifico se o CPF / CNPJ do cliente está nulo, para, aí sim, exibí-lo na tela

success: function(json) {
   var lista = json.list;
   for(var i in lista) {
      var topo = $('<div class="assinante">');
      if (lista[i].cpfCnpj != null) { var var_cpfCnpj = $('<p>' + lista[i].cpfCnpj + '</p>'); }
      var rodape = $('</div>');
      var cliente = topo + var_cpfCnpj + rodape;
      cliente.appendTo('#resultado');
   }
}

Aliás, quando peço para retornar as 3 vars em uma só, dá erro, alguém sabe porque isso acontece? Quando eu ponho na var cliente apenas um dos 3 campos, da certo.

Obrigado mais uma vez.

Tem um tempinho que nao mexo com JS, mas se essa forma de for, estilo foreach, funciona em JS, a sua variavel i jah esta recebendo cada item.
Ou seja, ou faz:
for(i=0; i<lista.size(); i++){
var item = lista[i];
}

ou

for(var item in lista){
//item jah eh meu elemento
}

Entendi! essa forma já está iterando e já está tudo ok, minha dúvida era se havia alguma forma que não utilizasse Javascript, mas pelo visto não há.

Preciso agora saber como resolver o problema que ocorre quando eu tento unir todas essas variáveis, como você pode ver na linha 7

success: function(json) {
   var lista = json.list;
   for(var i in lista) {
      var topo = $('<div class="assinante">');
      if (lista[i].cpfCnpj != null) { var var_cpfCnpj = $('<p>' + lista[i].cpfCnpj + '</p>'); }
      var rodape = $('</div>');
      var cliente = topo + var_cpfCnpj + rodape;
      cliente.appendTo('#resultado');
   }
}

Quando eu atribuo à var cliente apenas uma das 3 variáveis, ele passa. Quando eu aplico as 3 juntas, ele não passa.

vc quer a soma das variáveis mesmo?

faça isso:

success: function(json) {  
   var lista = json.list;  
   for(var i in lista) {  
      var topo = $('<div class="assinante">'),
          cpfCnpj = lista[i].cpfCnpj ? $('<p>' + lista[i].cpfCnpj + '</p>') : '',
          rodape = $('</div>');  
      var cliente = topo + cpfCnpj + rodape;  
      cliente.appendTo('#resultado');  
   }  
}

Na verdade, Lucas, eu gostaria de concatenar as strings.

Fiz exatamente como você sugeriu, o ajax não completa. Se eu deixar apenas uma das 3 variáveis (sem concatenar), funciona.

Para o resultado final ficar assim:

<div class="assinante">
 <p><span class="rotulo">CPF:</span>000.000.000-00</p> //caso o cliente tenha o CPF cadastrado, claro.
 ...
</div>

faz sentido.

quando vc faz:

$('<div>')

ele já cria a div, não é só a string.

faça isso:

success: function(json) {    
   var lista = json.list;    
   for(var i in lista) {    
      var cliente = $('<div class="assinante">');
      if (lista[i].cpfCnpj) 
           cliente.append($('<p>').html(lista[i].cpfCnpj))
      cliente.appendTo('#resultado');    
   }    
}  

Funcionou!

Sou muito fraco de Javascript :frowning:
Me perco sempre quando é para fazer as coisas mais simples.

Então o que você fez foi criar uma variável e ir adicionando conteúdo nela, e depois da variável toda pronta, eu dou append nela na div “resultado”, é isso?
Como eu fecharia esse

aberto na linha 6? (sinto que eu estou falando besteira).

isso não é só javascript. É jQuery. sugiro que vc dê uma olhada no que é possível fazer com ele. (http://docs.jquery.com)

var s = '<p>Isso é uma string, não dá pra dar append</p>'

var p = $('<p>'); //isso cria uma tag p (já aberta e fechada) e retorna o objeto jquery.

p.append('posso colocar qqer html aqui ou objetos jquery');
p.html('substitui o html de dentro da tag');

enfim, tem mta coisa q dá pra fazer

Cara, brigadão mesmo por todas as dicas! :smiley:

Primeiro, não faz atribuição com vírgula não, não é boa prática de programação. Use a vírgula só em casos específicos, dentro de um “for”, por exemplo, para evitar re-avaliação das expressões. Por exemplo:

for(var i=0, tam=vetor.size(); i<tam; i++){ //iterações }

No seu caso do JavaScript, você tá verificando se as strings são nulas, mas é bem possível que estejam vindo não nulas, mas vazias. Melhor checar direto como se a variável fosse já um valor booleano, ou se a string não está vazia:
if(minha_string)

ou

if(minha_string != null && minha_string != ‘’)