#!/usr/bin/perl -w
#
# Ejemplo de CGI::Ajax, extraído del ejemplo
# 'pjx_combo.pl' de la distribución CGI::Ajax
#
# Joaquín Ferrero. 20071004
#
# INSTALACIÓN: en algún lugar donde el servidor web pueda ejecutarlo
#
# este script muestra un conjunto dinámico de cajas select, donde la
# selección en una caja cambia los contenidos de la otra, o los valores
# html de un div. Los datos de cada select provienen de un hash, pero
# puede ser también de una conexión con una base de datos, etc.
#
# Nota, se requiere una versión de CGI::Ajax >= 0.49
#
use CGI ':standard';
use CGI::Ajax 0.49;
use strict;
# Nuestra base de datos
my %datos = (
tipo_1 => {
nombre => 'Homer Simpson',
direccion => 'Evergreen Terrace',
},
tipo_2 => {
apodo => 'Sean Connery',
objetivo => 'Downtown Street',
},
tipo_3 => {
empresa => 'Aprosi',
calle => 'Fanega, 1',
},
tipo_4 => {
usuario => 'zozo666',
procedencia => 'Desconocida',
},
);
# Lista de funciones a exportar al JavaScript
my %funciones = (
Select1 => \&select1,
Select2 => \&select2,
Resultado => \&resultado,
);
# Nuestros objetos CGI y CGI::Ajax
my $cgi = CGI->new();
my $ajax = CGI::Ajax->new( %funciones );
# Inicializa algunos parámetros del comportamiento CGI::Ajax
$ajax->JSDEBUG(1); # activa el depurado javascript, que colocará un
# nuevo elemento div al final de nuestra página mostrando
# el URL de la petición asíncrona
# Salida de nuestra página web
print $ajax->build_html( $cgi, \&muestra_html );
### Subrutinas
# Salida del HTML.
# He añadido una función javascript para borrar los contenidos.
# Esto evitará efectos extraños al sobreescribir un div sin antes
# vaciarlo.
# P.D.: para ser completamente puristas, este código debería ser
# generado con funciones del propio módulo CGI
sub muestra_html {
my $html = <<EOT;
<HTML>
<HEAD><title>Ejemplo CGI::Ajax de select en cascada</title>
<SCRIPT>
// define una funcion para limpiar adecuadamente los div
function reinicia_div( ) {
if ( arguments.length ) {
// reinicia un div especifico
for(var i = 0; i < arguments.length; i++ ) {
document.getElementById(arguments[i]).innerHTML = "";
}
}
else {
// reinicia todos los div
document.getElementById("div_lista1").innerHTML = "";
document.getElementById("div_lista2").innerHTML = "";
document.getElementById("div_resultado").innerHTML = "";
}
}
</SCRIPT>
</HEAD>
<BODY onload="reinicia_div(); Select1([],['div_lista1']); return true;" >
<form><table border="3">
<tr>
<td><div id="div_lista1"></div></td>
<td><div id="div_lista2"></div></td>
<td><div id="div_resultado" style="border: 1px solid black; width: 240px; height: 80px; overflow: auto"></div></td>
</tr>
<tr>
<td colspan="2"><input type="text" name="textfield"></td>
<td><input type="submit" name="Submit" value="Submit"></td>
</table></form>
</BODY>
</HTML>
EOT
return $html;
}
# Estas son las funciones exportadas - notar que Select1 y Select2
# solo están devolviendo el html que es insertado en sus correspondientes
# elementos div
sub select1 {
# Creamos un select, cuyo Onclick activa la petición Ajax
# En la petición Ajax Select2 pasamos el valor elegido en select_1 e
# indicamos que el resultado debe quedarse en el div_lista2
# Aquí usamos las facilidades del módulo CGI para crear código HTML
# sin verlo:
my $html
= Select(
{
-id => 'select_1',
-name => 'lista_1_nombre',
-size => 4,
-OnClick => q{reinicia_div('div_resultado'); Select2( ['select_1'], ['div_lista2'] ); return true;},
},
# Obtener los valores desde nuestros %datos.
# Podría ser también una consulta a una base de datos
# Por cada uno de ellos, lo map()eamos a una <option>
map { option($_) } sort keys %datos,
);
return $html;
}
sub select2 {
# Recibimos como argumento el valor activado en el select_1
my $valor_select_1 = shift;
# Igual que antes, creamos el html a mostrar en el div
# Es un select que, al activarse un valor, hace otra llamada Ajax,
# esta vez a la función Resultado pasándole los valores de los dos select,
# y dejando la respuesta en div_resultado
# En esta ocasión armamos el select creando el código HTML directamente,
# para compararlo con la forma anterior
my $html
= q{<select multiple id="select_2" name="lista_2_nombre" size=3 }
. q{onclick="Resultado( ['select_1','select_2'], ['div_resultado'] ); return true;">}
;
# Mostramos los valores desde %datos
foreach my $valor ( keys %{ $datos{ $valor_select_1 } } ) {
$html .= '<option value=' . $valor . '>' . $valor . "</option>";
}
$html .= "</select>";
return $html;
}
sub resultado {
# Recibimos varios argumentos.
# El primero es el valor de select_1
my $valor_select_1 = shift;
# Lo que vamos a devolver es el texto dentro del div
my $html = "";
# El segundo argumento puede ser un conjunto de valores,
# porque el select_2 tiene el atributo 'multiple'.
while ( @_ ) {
my $valor_select_2 = shift;
$html .= $datos{ $valor_select_1 }{ $valor_select_2 } . "<br>";
}
return $html;
}
__END__