Jun
06

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.

5 Responses to “Javascript: Lista, Drag and Drop e Ajax para Ordernar”

  1. michel melo Says:

    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”

  2. Daniel S. Says:

    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!!

  3. Ricardo Spinoza Says:

    Olá tbem estou com o mesmo erro(Sortable is not defined), e no IE não está funcionando…

  4. Ricardo Spinoza Says:

    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

  5. Ricardo Spinoza Says:

    Mais um detalhe, a ordem dos includes influência no resultado desejado.

    mantenha está ordem para funcionar.

    Mais uma vez, obrigado,

    T+

Deixe seu Comentário