El widget Accordion de Spry es sencillo de utilizar y de entender. Sin embargo, intentar convertirlo en dinámico (de forma que se añadan los paneles según los datos) tiene truco.
Un acordeón básico de un solo panel tiene esta estructura:
El ejemplo anterior funcionará sin problemas, pero: ¿Qué sucede si intentamos aplicarle una región repetida?
<div class="Accordion" id="Accordion1" spry:region="empleados">
<div class="AccordionPanel" spry:repeat="empleados">
<div class="AccordionPanelTab">{nombre}</div>
<div class="AccordionPanelContent">{datos}</div>
</div>
</div>
<script type="text/javascript">
<!--
var acc = new Spry.Widget.Accordion("Accordion1");
//-->
</script>
En este caso, El widget no funcionará. La explicación es sencilla: El widget se crea al mismo tiempo que la región repetida, por lo que aquél es incapaz de controlar todos los paneles que aún no han sido creados. Debemos por tanto encontrar la forma de saber cuándo Spry ha terminado de crear todos los paneles para convertirlos en un acordeón. Para ello tenemos los observers.
Existen elementos de Spry (como las regiones y los datasets) que lanzan notificaciones cuando cambian. Estas notificaciones, similares a los eventos, pueden ser ‘observadas’ por un observer (valga la redundancia), que entrará en funcionamiento cuando se produzca alguna notificación.
En nuestro caso, necesitamos comprobar los cambios en una región, la cual puede realizar las siguientes notificaciones:
- onLoadingData: La región está cargando los datos desde el dataset
- onPreUpdate: Los datos se han cargado y la región está a punto de reescribirse con el nuevo html
- onPostUpdate: La región ya se ha regenerado con el nuevo html y se ha insertado en el documento
- onError: Ha ocurrido algún error durante el proceso
Por lo tanto, cuando la región envie la notificación onPostUpdate podremos crear el acordeón sin problemas, ya que todo el html ha sido generado.
Aquí entran en juego los observers: Son objetos o funciones (se aceptan ambos y su funcionalidad es similar), que se encargan de vigilar las notificaciónes enviadas por parte de la región y qué hacer cuando eso sucede. Para nuestro ejemplo, utilizaremos un objeto.
Un objeto observer tiene esta estructura:
//creamos el objeto
var miObserver = new Object;
//le decimos miObserver lo que tiene que hacer cuando recibe un onPostUpdate
//En nuestro caso, debe crear un acordeon
miObserver.onPostUpdate = function()
{
var acc1 = new Spry.Widget.Accordion("Accordion1");
};
//Finalmente, indicamos que miObserver estará pendiente del elemento 'Accordion1'
Spry.Data.Region.addObserver("Accordion1", miObserver);
A partir de ahora,cuando el elemento ‘Accordion1′ se regenere y envie la notificación onPostUpdate, el observer que hemos creado (miObserver) se encargará de crear el acordeon.
El codigo final es:
<head>
(...)
<script type="text/javascript">
<!--
//creamos el dataset
var empleados = new Spry.Data.XMLDataSet("empleados.xml", "empleados/empleado");
//creamos el observer
var miObserver = new Object;
miObserver.onPostUpdate = function()
{
acc = new Spry.Widget.Accordion("Accordion1");
};
Spry.Data.Region.addObserver("Accordion1", miObserver);
//-->
</script>
(...)
</head>
<body>
<!--Creamos el bloque del futuro acordeon -->
<div class="Accordion" id="Accordion1" spry:region="empleados">
<div class="AccordionPanel" spry:repeat="empleados">
<div class="AccordionPanelTab">{nombre}</div>
<div class="AccordionPanelContent">{datos}</div>
</div>
</div>
</body>
Excelente Andrés, ahora una pregunta supongo que es el mismo caso con los tabbed panels? cuando intentas crear una nueva pestaña a partir de datos dinámicos.
Saludos, Edgar
Hola Edgar:
La respuesta es sÃ:
Los métodos que controlan los widgets necesitan conocer toda su estructura para poder funcionar, por lo que la situación es la misma.
En este caso la estructura es:
<div id=”TabbedPanels1″ class=”TabbedPanels” spry:region=”ds1″>
<ul id=”tabs” class=”TabbedPanelsTabGroup” spry:repeatchildren=”ds1″>
<li class=”TabbedPanelsTab” tabindex=”0″>{username}</li>
</ul>
<div id=”contenido” class=”TabbedPanelsContentGroup” spry:repeatchildren=”ds1″>
<div class=”TabbedPanelsContent”>{nombre} {apellidos}</div>
</div>
</div>
Y el observador sólo necesita cambiar la creación del widget:
<script type=”text/javascript”>
<!–
var ds1 = new Spry.Data.XMLDataSet(“empleados.xml”, “empleados/empleado”);
regObserver= new Object()
regObserver.onPostUpdate = function()
{
var TabbedPanels1 = new Spry.Widget.TabbedPanels(“TabbedPanels1″);
};
Spry.Data.Region.addObserver(“TabbedPanels1″, regObserver);
//–>
</script>
Me quito el sombrero ;-) gracias Andrés
Hola.
Felicitaciones por el sitio, me ha resultado realmente interesante.
Me gustarÃa saber si con este js es posible generar el acordeon horizontal, y con distintos colore para cada titulo.
Gracias.
Hola Maximiliano:
Modificar el Accordion es algo complicado: ¿Por qué no una serie de paneles o un menu horizontal?
Se podrÃa crear un nuevo widget, pero me parece algo exagerado…
Sobre los colores: Puedes añadir tus propias clases a los div que tienen la clase AccordionPanelTab. Debes añadirlos por delante, eso si:
titulo
titulo
Para que tengan preferencia, puedes, eliminar el atributo de color de fondo de .AccordionPanelTab, aumentar la especifidad o definirlos como !important
Hola, y se puede adaptar los spry con PHP ?
saludos desde bogota..
:-)
Martin,
Claro que se puede :-) aquà tienes un tutorial: http://macdiggs.com/index.php/2006/07/05/integration-of-spry-and-phpmysql/
hola, es posible comparar dos campos de tipo texto (por ejemplo contrasena y repita contrasena) en un spry, y como se podria hacer esto. O por ejemplo q la fecha de nacimiento no sea mayor a la de hoy dia. es posible hacer este tipo de comparaciones utilizando SpryValidationTextField.js?, como se podria hacer esto?. gracias
DeberÃa ser posible, pero no por defecto, Limnes:
Esto que voy a decir lo digo sin haber probado, asà que puede que sea incorrecto:
Me parece que el único camino pasa por crear nuevos descriptores para esas validaciones al archivo SpryValidationTextfield.js: Bastante complicado.
A ver si con el tiempo puedo investigarlo un poco más, porque utiliza algunas expresiones regulares que ya marean sólo con mirarlas 8-0
Gracias por el link, Edgar!
Ahà va otro (que incluye además versiones para CF y ASP):
http://labs.adobe.com/technologies/spry/samples/utils/query2xml.html
Hola, no soy buena con el ingles, y he tenido problemas al crear el xml bueno al parecer se crea con php en eso voy, lo crea pero queria adaptar un sitio ya existente, el cual utiliza en su contenido tags y tildes y caracteres que hacen que el xml salga con un error.. la pregunta bueno es que puedo hacer en este caso? ya que el dreamweaver me dice que no puede leer la estructura del xml.
ahora yo hago la prueba con campos titulos que no tienen tildes y asi sale bien el xml en el browser. ahora aplico los spry en dream pero no me sale informacion al llamar la pagina php solo me sale {ds1::album} asi , que debo tener en cuenta mas en el servidor ?
gracias posiblemente son preguntas basicas.. pero no he podido por mas cabeza le he puesto y buscar info.. thansks..
Algo apenada.. pero por algun motivo encoding=”ISO-8859-1″ funciona!! milagro.. frente a lo que tenia encoding=”iso-8859-1″ no funcionaba.. creo que dormir y empesar el dia nuevamente era lo que necesitaba fue sencillo, bueno ahora estoy con lo del servidor aun me sigue saliendo {ds1::album} al visualizarlo en el navegador seguire.. en mi trabajo.. saludos
Puede verse en alguna url, Carolina?
Hola, bueno estoy entrando a un nuevo mundo la verdad, pero encontre este link http://www.adobe.com/designcenter/video_workshop/index.html?id=vid0165 donde vi un video de como trabajar el xml y otro para usar el spry framework, la verdad que riko ver aunque no entiendo el ingles vi paso a paso lo que tenia que hacer y claro habia obviado unos pasos por esos mis problemas!! bueno no puede darles indicaciones pero les dejo este link muy util!! a mi parecer
http://www.adobe.com/designcenter/video_workshop/index.html?id=vid0165
Hola Andrés.
No te lo creerás pero llevo horas buscando en google una solución y ahora acabo de encontrar tu artÃculo; eso me pasa por no acudir antes a tu web, que la tengo en mis favoritos hace tiempo… Gracias mil.
Una consulta: los datos que recojo son de una base de datos que trabaja con Navision (microsoft). Cómo resuelvo el problema?
Prado:
El origen de los datos es completamente indiferente: La cuestión es si dispones de algún método (no he trabajado con Navision) que te permita acceder a los mismos y devolverlos en un formato adecuado (Spry acepta no sólo XML, sino también JSON en incluso html)
Hola,
Me ha venido muy bien encontrar este post. El problema que me surge ahora es que despues de crear el acordeón dinámico, todo lo que tengo por debajo de él( por ejemplo el pie de pagina), el acordeón se superpone en vez de quedarse en el final. ¿alguna sugerencia?
gracias!
@Manuel:
Puede ser un problema de posicionamiento en CSS con el contenido inferior, ya que el accordion no marca ninguna posición para sà mismo.¿Algún valor absoluto, quizá?
Tambien comprueba que el contenido del pie no esté dentro del bloque div del accordion.
Cuando pongo el div del pie de pagina dentro del acordeon es cuando lo hace BIEN. Sino la web “dibuja” primero la cabecera, el pie y luego el acordeón y al ser dinamico y mas grande el main content no crece.
Hola Andres. Genial esta página. Tengo un problema con el acordeon que no se como solucionar. Necesito que al seleccionar un registro del acordeon, este se deslize hasta la parte superior del acordeon antes de desplegars, es decir que el contenido del panel siempre ocupará el mismo espacio dentro de la página. supongo que hay que modificar el código de SpryAccordion.js pero no se como hacerlo. Agradeceria mucho la ayuda ya que me he quedado estancado en este punto. un saludo
Hola Andres. Necesito saber si hay alguna manera de deslizar el panel seleccionado hasta el inicio del acordeon antes de desplegarse su contenido. Con esto se consigue que el contenido siempre ocupe el mismo espacio en la pagina.
Muchas gracias por tu colaboración.
@manuel:
Puedes enviarme un ejemplo? (tecnorama/arroba/hotmail.com)
@Alfred:
En principio ése es el efecto por defecto: La cabecera del panel se desplaza, pero no deberÃa cambiar la altura… Puedes en cualquier caso indicar una altura por defecto al crear el acordeon y no depender del contenido del panel abierto utilizando la opcion “fixedPanelHeight” y pasando el numero de pixeles que quieres que tenga al crearse:
acc = new Spry.Widget.Accordion(“Accordion1″, {fixedPanelHeight:100});
Hola Andres. Me refiero a que el panel seleccionado, se desplace y ocupe la posición del Panel 1 del acordeon y todos los paneles anteriores al seleccionados queden ocultos por encima del desplegado. No se si me he explicado bien. Puedes ver un ejemplo del efecto deseado en la pagina http://www.tomato.co.uk, aunque este no esta hecho con el Spry Accordion.
Hola. Es posible que alguien me conteste si se puede o no hacer lo que he planteado antes?. Es que llevo 3 semanas intentando encontrar una solución y estoy muy desesperado.
Buenas, tengo 2 inconvenientes con los “Spry Widget”, el primero es al usar Spry.Widget.TabbedPanels tengo 6 solapas la cual tienen mucha info cada una y conectan auna base de datos mysql, el tema es que al entrar a la pagina si bien veo solo el contenido de la solapa activa, descarga el contenido de todas las solapas, este contenido son imagenes por lo que tarda bastante en mostrar la pagina. hay forma de hacer que se valla cargando la pagina mientras hago clic en las solapas?.
el segundo problema lo tengo con Spry.Widget.Accordion, este lo creo de forma dinamica trayendo tanto el titulo como el contenido de la base, el tema es que el contenido no pone la barra de desplasamiento, es mas seria interesante que el area para ver el contenido varie segun la cantidad de contenido. Se puede hacer algo con esto?
@ore’s:
En ese caso puede que fuera interesante utilizar el método Spry.Utils.updateContent(target,url), de manera que vas cargando la url a medida que seleccionas un panel (y añadir alguna uncion personal que active sólo la primera carga)
Para el segundo caso, puedes probar a modificar el css para que añada la barra cuando el contenido supere las medidas del panel o pasar el parametro useFixedPanelHeights:
var ac1 = new Spry.Widget.Accordion(“myAccordion”,{useFixedPanelHeights:false});
De esta manera, cada panel del acordeón se adaptará a su contenido