Javascript: Lista, Drag and Drop e Ajax para Ordernar
Autor: Jonathan Isaac
Categoria: Ajax, CSS, JavaScript, PHP, Prototype, Script.aculo.us |
Este artigo veio através da necessidade de um de nossos clientes, que pediu o seguinte:
“Na listagem de produtos eu quero poder organizar a forma eles irão aparecer. Detalhe: Já cadastrei tudo.”
A partir desta exigência foi pensado o seguinte:
“Primeiro preciso fazer com que as linhas se movimentem dentro do bloco principal (drag and drop), depois eu atualizo o banco de dados (Ajax)”
O sistema estava desenvolvido em tabelas (tables) para a listagem de produtos (erro comum) por isso esse artigo foi escrito visando tabelas e não lista (ul,li), porém o artigo serve em igual para ambas formas de listagem (aconselha-se lista).
Ao que interessa:
Utilizaremos o framework prototype em conjunto ao framework scriptaculous (download aqui), lembrando que basta baixar o scriptaculos que já inclui o prototype.
Criaremos a página lista.php (o uso do PHP é uma preferência) e incluiremos entre o prototype.
<script language="javascript" src="prototype.js"></script> <script language="javascript" src="scriptaculous.js"></script>
Pra ficar menos feio vamos colocar um CSS básico (também entre as tags
<style type="text/css"> table { width:80%; border:1px solid #ccc; color:#FFFFFF; font:18px Verdana, Arial, Helvetica, sans-serif #ccc; font-weight:bold; } tr { background-color:#000000; cursor:move; } td{ height:40px; } </style>
Em seguida criaremos o HTML de nossa lista (uma tabela):
<table> <tbody id="lista_id"> <tr id="lista_0"> <td>Seja bem vindo</td> </tr> <tr id="lista_1"> <td>Zuntto</td> </tr> <tr id="lista_2"> <td>Você é legal</td> </tr> <tr id="lista_3"> <td>Acesse agora http://blog.zuntto.com</td> </tr> </tbody> </table>
Repare que colocamos o tbody que representa o corpo da tabela e a limitação para que a movimentação das linhas se mantenham lá. Reparem também que o id das tr é representada por “nome_posição” (a posição que eu criei é fictícia, você irá gerar as posições na medida que você irá listar os itens através do PHP (entre outras linguagens).
Agora que vem a parte legal da coisa, no final do documento insira o seguinte código:
<script type="text/javascript" language="javascript"> Sortable.create('lista_id',{tag:'tr', ghosting:true,constraint:'vertical', onUpdate:ordenar,tree:true}) </script>
A função Sortable junto ao método create, criar uma lista “sorteada”, ou seja, uma lista onde é possível organizar os elementos (drag and drop), no nosso casso eu passei qual o id de nosso tbody (campo de movimentação), nosso elemento que irá se movimentar (tr), o parametro ghosting que é para aparecer o objeto em movimento (ou como se diz, seu fantasma), passei como parametro o constraint que indicar se era horizontal ou vertical a movimentação e finalizei dizendo: Quando acontecer o “drop” (usuário soltar o elemento que esta mudando de posição) chame a função ordernar() e em seguida dizendo que terá uma árvore de ordenação … argf cansativo escrever tudo isso.
Se você não necessita de ordenação, basta remover o onUpdate e assim vai.
Agora iremos criar nossa função de ordernação (colocada entre o )
<script language="javascript"> function ordenar() { var lista_char = '%26'; var lista_body = 'lista_id'; var lista_data = Sortable.serialize(lista_body)+unescape(lista_char); var options = { method : 'post', parameters : lista_data }; new Ajax.Request('ordem.php',options); } </script>
Resumindo, temos uma função ordenar que serializa os dados contidos em tbody (no caso ele pega as posições 0, 1, 2, 3 …). O processo da função serialize é simples, ele resgata os dados (value) contidos nos id´s de seus elementos filho, como no nosso caso o filho é uma tr, ele resgata o innerHTML (conteudo de cada uma delas) fazendo com que tudo vire um vetor onde a posição do vetor representa o valor contiudo no id (o numero em lista_numero repatido por lista_char, ou underscore) e o valor contido nesta posição o proprio innerHTML.
Feito isso basta fazer o ordem.php que será o arquivo requisitado pelo Ajax.
No meu caso ficou da seguinte forma:
<? mysql_connect("localhost","mysql","senha"); $i = 0; foreach ($_POST['lista_id'] as $vet) { $k = $i+1; mysql_query("update produtos set pro_ordem = ".$k." where id ='".$vet['id']."'"); $i++; } ?>
Para se estudar melhor os valores que estão chegando na pagina ordem.php utilize:
var_dump($_REQUEST); die();
Detalhes adicionais
Como eu havia comentado o banco de dados já estava populado, então eu criei uma nova coluna chamada pro_ordem e rodei o seguinte script manualmente (em php) para todos os registros terem uma ordem manual:
<? mysql_connect("localhost","mysql","senha"); $i = 1; $qry = mysql_query("select * from frw_produtos"); while ($obj = mysql_fetch_object($qry)) { mysql_query("update frw_produtos set pro_ordem = ".$i." where id ='".$obj->id."'"); $i++; } ?>
Veja na prática
Na prática obtivemos o seguinte resultado: Clique aqui para o exemplo.
Neste exemplo reparem que ele executa o request do método Ajax porém não retorna nada, isso se deve ao fato de não ter colocado o arquivo ordem.php online (nem precisa também né);
Testado no FF e no IE 6.
Qualquer dúvida estamos ai.
julho 10th, 2008 at 12:25
olá esta dando um erro nesta linha
Sortable.create(’lista_id’,{tag:’tr’, ghosting:true,constraint:’vertical’, onUpdate:ordenar,tree:true})
“Sortable is not defined”
novembro 10th, 2008 at 8:59
Perfeito cara, um cliente havia me pedido um mecanismo assim para poder ordenar os resultados conforme sua necessidade…
Só que uso a biblioteca JQuery… agora tenho que resolver os conflitos com a prototype.. mas ta massa
Valeu!!
novembro 25th, 2008 at 15:48
Olá tbem estou com o mesmo erro(Sortable is not defined), e no IE não está funcionando…
novembro 25th, 2008 at 16:10
Ops, esqueçi de agradecer pelo artigo, está bem didático, parabéns!!!!
Descobri o porquê do erro, nos includes que vc cita:
está faltando os demais includes sendo:
e não sei se tem algo a ver, mas a versão dos js do exemplo são: scriptaculous.js ‘1.7.0′, e prototype.js ‘1.5.0′
E eu acabei baixando as versões mais atuais.
Não sei se influencia, mas na versão atual ‘1.8.2′ do scriptaculous.js e ‘1.6.0.3′ do prototype deu o problema que o colega acima mencionou…
Bom é isto
OBrigado
novembro 25th, 2008 at 16:21
Mais um detalhe, a ordem dos includes influência no resultado desejado.
mantenha está ordem para funcionar.
Mais uma vez, obrigado,
T+