Completando formulario al cambiar el valor de un campo

349 views
Skip to first unread message

Leandro E. Colombo Viña

unread,
Feb 7, 2014, 1:14:42 PM2/7/14
to web2py-...@googlegroups.com
Estimados,

sigo en mi camino de aprendizaje de web2py y ahora estoy tratando de hacer un formulario para completar unos varios datos en una tabla.
Tengo en el modelo lo siguiente:
db.define_table('general_date',
                Field('type', required=True, requires=IS_IN_SET(GENERAL_DATE_TYPE), label=T("Date Type")),
                Field('year', 'integer', length=4, required=True, requires=IS_IN_SET(['2013', '2014', '2015', '2016', '2017', '2018']), label=T("Year")),
                Field('date', 'date', required=True, requires=IS_DATE(DATE_FORMAT), label=T("Date")),
                Field('start_time', 'time', requires=IS_EMPTY_OR(IS_TIME()), label=T("Start Time")),
                Field('end_time', 'time', requires=IS_EMPTY_OR(IS_TIME()), label=T("End Time")),
                auth.signature
                )  


donde GENERAL_DATE_TYPE es una lista con los valores que puede tomar.

GENERAL_DATE_TYPE = ['reunion1', 'reunion2', 'asamblea', 'examen', 'encuesta']

La idea es tener por año un conjunto único de datos, es decir, sólo uno de los definidos en GENERAL_DATE_TYPE. Así en 2013 tenemos una reuníon1, una reunión2, una asamblea, un examen y una encuesta. Lo mismo para el 2014 y así sucesivamente. También se podría pensar en algo como una lista de feriados...

Entonces en el controlador tengo todo el formulario. Que tiene un campo año que me deja elegir entre la lista de años posibles definida en el modelo y a partir de ahí completa los valores que existen. Hasta ahora eso lo tengo funcionando pero para el año actual. El tema es si quiero hacer algún cambio en otros años, no sé como hacer el update de los valores del formulario sin que me falle o no funcione. He aquí el controlador...

def new_dates():
    ## Creo el formulario para la selección del año.
    form = SQLFORM.factory(db.general_date.year)
   
    ## Para cada tipo de fecha posible en un año, genero los campos a completar y lo agrego al formulario anterior.
    for date_type in GENERAL_DATE_TYPE:
        fila = TR(LABEL(B(date_type)))
        fila += TR(LABEL(T("Date")+":"), INPUT(_name=date_type.replace(' ','_')+'_date', _class="date", requires=IS_EMPTY_OR(IS_DATE(DATE_FORMAT))), _id=date_type.replace(' ','_')+"_date__row")
        fila += TR(LABEL(T("Start Time")+":"), INPUT(_name=date_type.replace(' ','_')+'_start_time', _class="time", requires=IS_EMPTY_OR(IS_TIME())), _id=date_type.replace(' ','_')+"_start_time__row")
        fila += TR(LABEL(T("End Time")+":"), INPUT(_name=date_type.replace(' ','_')+'_end_time', _class="time", requires=IS_EMPTY_OR(IS_TIME())), _id=date_type.replace(' ','_')+"_end_time__row")
        form[0].insert(-1, fila)

    ## Si no envié ningún año, que automáticamente seleccione el año actual en el momento de cargar la página.
    if not request.vars.year:
        form.vars.year = request.now.year
    else:
        form.vars.year = request.vars.year
   
    ## Con el año seleccionado busco en la tabla los valores que haya correspondientes a ese año y completo los campos del formulario.
    data = db(db.general_date.year==form.vars.year).select(db.general_date.type, db.general_date.date, db.general_date.start_time, db.general_date.end_time)
    ## Completo los campos que contienen datos.
    for row in data:
        fieldtype = row.type
        fieldtype = fieldtype.replace(' ', '_')
        form.vars[fieldtype+'_date'] = row.date.strftime(DATE_FORMAT)
        if not row.start_time:
            form.vars[fieldtype+'_start_time'] = row.start_time
        if not row.end_time:
            form.vars[fieldtype+'_end_time'] = row.end_time
    ## Si el formulario valida construyo la consulta de inserción.
    if form.validate():
        for field, value in form.vars.items():
            fieldtype = ""
            date = ""
            start_time = ""
            end_time = ""
            if not value:
                continue
            elif "_date" in field:
                fieldname = field.split("_date")
                fieldtype = fieldname[0].replace('_', ' ')
                date = value
                start_time = form.vars[fieldname[0]+"_start_time"]
                end_time = form.vars[fieldname[0]+"_end_time"]
            elif "_start_time" in field:
                continue
            elif "_end_time" in field:
                continue
            elif "year" in field:
                continue
            else:
                pass
            ## Me fijo que el tipo de fecha y el año coincidan para sobrescribir ese campo y no generar uno nuevo.
            ## Si no existe, creamos uno nuevo con los valores.
            db.general_date.update_or_insert((db.general_date.type==fieldtype)&(db.general_date.year==form.vars.year), type=fieldtype, year=form.vars.year, date=date, start_time=start_time, end_time=end_time)
        response.flash = T("new record inserted")
    return dict(form=form)


Tal vez haya una manera más fácil de hacerlo y sólo me dediqué a complicarme la vida. No lo sé, pero no se me ocurrió otra manera... Por ahora como lo tengo mínimamente funciona. El problema es que quiero hacer que cuando elijo de la lista desplegable del año un año diferente al actual que se actualice sólo sin tener que apretar ningún botón... cómo puedo hacerlo? Intenté con algo de jQuery (que no conozco y me limito a hacer un poco de copy-paste e intentar) pero tampoco tuve éxito.

Muchas gracias!

samuel bonill

unread,
Feb 7, 2014, 2:33:08 PM2/7/14
to web2py-...@googlegroups.com
eso es mas que todo a nivel de ajax, puedes solucionarlo con Angular.js 


--
Has recibido este mensaje porque estás suscrito al grupo "web2py-usuarios" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus correos electrónicos, envía un correo electrónico a web2py-usuari...@googlegroups.com.
Para obtener más opciones, visita https://groups.google.com/groups/opt_out.

Leandro E. Colombo Viña

unread,
Feb 7, 2014, 2:36:28 PM2/7/14
to web2py-...@googlegroups.com
Samuel, gracias por responder...

Me imaginé que tenía que usar Ajax... el problema es que no tengo mucha experiencia con eso. Algún dato más? Algún ejemplo de donde basarme? Ya leí la documentación del libro de web2py pero no me alcanza...

Saludos!

Federico Ferraro

unread,
Feb 7, 2014, 3:13:44 PM2/7/14
to web2py-...@googlegroups.com
Es un solo evento por año :

2013 >> reunión
2014 >> examen
2015 >> asamblea

y queres que cuando se cambie el año en el formulario los otros campos se actualicen con los datos de la tabla ??

Slds ...
--
Federico Ferraro
Usuario Linux : 482533.
--

Leandro E. Colombo Viña

unread,
Feb 7, 2014, 3:17:34 PM2/7/14
to web2py-...@googlegroups.com
No, es un set de datos por año... En 2013 hay reunión, asamblea y examen.
En 2014 también, y en 2015 también y así sucesivamente.
Por eso decía que es como los feriados, son los "mismos" de nombre pero cambia la fecha cada año...

samuel bonill

unread,
Feb 7, 2014, 3:40:22 PM2/7/14
to web2py-...@googlegroups.com
Mira este ejmplo, cuando seleccionas una opcion nueva llama a un controlador via ajax e inserta la respuesta en un div :

dos funciones en el controlador para este ejemplo :


def index():
    form = SQLFORM.factory(Field('opciones', \
              requires=IS_IN_SET(['opcion1', 'opcion2', 'opcion3'])))
    return dict(form=form)


def callback():
     req = request.args(0)
     return req



luego la vista index.html


{{extend 'layout.html'}}

{{=form}}

<div id='ajx'></div>

<script>
jQuery('select[name=opciones]').on('change', function() {
  var nombre=$(this).val();
  var dataString = nombre;

  $.ajax
    ({
     type: "POST",
     url: "{{=URL('callback')}}/" + dataString,
     data: dataString,
     cache: false,
     success: function(html)
    {
      $("#ajx").html(html);
    }
    });
});
</script>



Espero que  te sirva de guia este ejemplo.... DIme si te funciono !!!

isi_jca

unread,
Feb 7, 2014, 4:06:30 PM2/7/14
to web2py-...@googlegroups.com
Leandro:

No entiendo que es lo que queres hacer. El archivo adjunto contiene una imagen de como se ve mas o menos tu formulario. Si haces click en el botón submit se blanquea el formulario.y supuestamente debe grabar todos los tipos de eventos. Ahora bien ¿qué debería suceder si cambias de año?. ¿Si los datos ya existen, recuperarlos?, ¿Establecer automaticamente en date la misma fecha pero con distinto año?.

Saludos

isi_jca

unread,
Feb 7, 2014, 4:10:01 PM2/7/14
to web2py-...@googlegroups.com
Leandro:

Perdón me olvide adjuntar el archivo




El viernes, 7 de febrero de 2014 17:17:34 UTC-3, Leandro E. Colombo Viña escribió:
New Date.pdf

Leandro E. Colombo Viña

unread,
Feb 7, 2014, 5:58:37 PM2/7/14
to web2py-...@googlegroups.com
Gracias desde ya por las respuestas. Samuel, en breve pruebo lo que me decís y te cuento cómo me fue.

Julio, lo que mandás en el adjunto es exactamente lo que tengo armado. Ahora lo que yo quiero es que cuando seleccione el año, por ejemplo 2015, me muestre si hay alguna fecha cargada, por ejemplo reunión2. Y si agrego nuevos datos o modifico esos que me muestran cuando apreto el botón de enviar que haga los cambios en la DB.

No sé si logré explicarme. La idea del formulario es que sea un formulario de consulta y actualización. Y por cómo está armado verás que no es necesario completar todas las fechas en un mismo envío. Así por ejemplo si completas 2 fechas del 2014, cuando volvés a consultar te aparecen esas fechas cargadas y podés completar el resto o modificar las anteriormente cargadas.

Muchas gracias por la ayuda!

Leandro E. Colombo Viña

unread,
Feb 7, 2014, 6:12:33 PM2/7/14
to web2py-...@googlegroups.com
Samuel,
creo que entiendo lo que me decís hacer, pero me cuesta implementarlo ya que la sintáxis de jQuery y Ajax no las domino ni por asomo... jajaja.

Cuando se carga la página, por valor en año se setea el actual (2014). Con ese valor el controlador hace una consulta en la DB y completa los campos que tengan datos en la tabla para ese año.
Por lo que entiendo de la sugerencia, tendría que hacer una nueva función que reciba el nuevo dato del año cuando se cambia (por ejemplo de 2014, a 2013) y con este nuevo valor (2013) consulte a la DB y reescriba los campos que ya existen con los valores correspondientes de la tabla o deje los campos vacíos.

En el formulario, los nombres de los campos son los tipos de fecha que puedo tener que se les agrega un sufijo '_date', '_start_time' o '_end_time'. Así por ejemplo si tengo como tipos de fechas reunion1, examen y encuesta tendré en el formulario los campos:
  • no_table_year
  • reunion1_date
  • reunion1_start_time
  • reunion1_end_time
  • examen_date
  • examen_start_time
  • examen_end_time
  • encuesta_date
  • encuesta_start_time
  • encuesta_end_time
¿Cómo los referencio? Porque para completar luego de la consulta a la DB en el controlador yo hice:

data = db(db.general_date.year==form.vars.year).select(db.general_date.type, db.general_date.date, db.general_date.start_time, db.general_date.end_time)
    ## Completo los campos que contienen datos.
    for row in data:
        fieldtype = row.type
        fieldtype = fieldtype.replace(' ', '_')
        form.vars[fieldtype+'_date'] = row.date.strftime(DATE_FORMAT)
        if not row.start_time:
            form.vars[fieldtype+'_start_time'] = row.start_time
        if not row.end_time:
            form.vars[fieldtype+'_end_time'] = row.end_time

Pero ahora con Ajax, estoy a ciegas...

samuel bonill

unread,
Feb 7, 2014, 10:53:29 PM2/7/14
to web2py-...@googlegroups.com
ajax no es tan complicado con web2py, enviame el codigo enpaquetado como una aplicacion web2py... aver que puedo hacer

isi_jca

unread,
Feb 7, 2014, 11:36:09 PM2/7/14
to web2py-...@googlegroups.com
Leandro:

              Fijate en el proyecto adjunto, al ejecutarlo ingresa por Cliente --> New Dates. Creo que esta opción se comporta según tu planteamiento. Espero que te sirva.

Saludos cordiales.
web2py.app.Prueba.w2p

isi_jca

unread,
Feb 8, 2014, 6:55:41 AM2/8/14
to web2py-...@googlegroups.com
Leandro:

Si el proyecto que adjunte funciona como vos queres el siguiente reto es integrar los dos formularios (el de filtrado y de insert) en una sola vista.

Saludos.

Leandro E. Colombo Viña

unread,
Feb 8, 2014, 3:58:44 PM2/8/14
to web2py-...@googlegroups.com
Julio,

si es exactamente la funcionalidad que estoy buscando! Me voy a poner a investigar cómo fusionar esas vistas, y sino, lo implementaré como me sugerís y listo...

Muchísimas gracias!

Leandro E. Colombo Viña

unread,
Feb 8, 2014, 5:20:35 PM2/8/14
to web2py-...@googlegroups.com
Samuel,

podrías ayudarme con el código? 
Creo que lo que finalmente tengo que hacer es en el script que tengo en la vista, mandar a llamar de nuevo el formulario pero esta vez con el valor que acaba de cambiar en el mismo. Lo que yo necesito sería poder ingresarle una instrucción como esta: redirect(URL('new_dates',vars=dict(year = form.vars.year))

<script>
    $(document).ready(function(){
        $('#no_table_year').change(function(){
            ajax('new_dates', ['year'], '#')
            /*$('form').submit()*/
        });
    });
</script>

samuel bonill

unread,
Feb 8, 2014, 6:17:11 PM2/8/14
to web2py-...@googlegroups.com
Asegurate de tener un div donde almacenar el callback....

ej:

<div id="respuesta"></div>

<script>
    $(document).ready(function(){
        $('#no_table_year').change(function(){
            ajax("{{=URL('new_dates')}}", ['year'], 'respuesta');
        });
    });
</script>

Recuerda que tienes que tener una funcion llamada new_dates.

el select tiene que tener como nombre year : <select name='year' ... > ... etc, para que cuando cambies de opcion se realice el callback automaticamente


isi_jca

unread,
Feb 8, 2014, 7:23:23 PM2/8/14
to web2py-...@googlegroups.com
Leandro:

Te mando una segunda versión donde estan integrados los dos formularios, espero te sirva.

Saludos cordiales.
web2py.app.Prueba_V2.w2p

Leandro E. Colombo Viña

unread,
Feb 9, 2014, 11:29:54 AM2/9/14
to web2py-...@googlegroups.com
Julio, 

si la verdad que me sirve y muchísimo, la idea era tratar de omitir el botón del primer formulario y que la búsqueda se haga simplemente cuando uno cambia el valor del campo año. Pero creo que lo voy a dejar implementado así como me sugerís vos que si bien no es exactamente lo que yo quería, funciona perfectamente para lo que necesitaba. Has sido de gran ayuda!!!!

MUCHÍSIMAS GRACIAS!

Samuel,

ese DIV de "respuesta" que vos me decís lo tengo que agregar en la vista y puede contener a mi formulario? Algo así como si en la vista pongo {{=DIV(form)}} entonces de esa manera AJAX me sobreescribe los campos del form?

samuel bonill

unread,
Feb 9, 2014, 2:03:38 PM2/9/14
to web2py-...@googlegroups.com
si agrega el div en la vista, y el callback depende de lo que retorne la funcion...
Message has been deleted

isi_jca

unread,
Feb 10, 2014, 9:23:40 AM2/10/14
to web2py-...@googlegroups.com
Leandro:

Te mando una tercera versión donde esta implementado el evento onchange.


Saludos cordiales.
web2py.app.Test.w2p

Leandro E. Colombo Viña

unread,
Feb 10, 2014, 12:12:57 PM2/10/14
to web2py-...@googlegroups.com
Julio,

lo tuyo es SUBLIME! EXCELENTE! FANTÁSTICO!!!!! Exactamente lo que yo quería implementar. Ya mismo me pongo a estudiar el código!

MUCHÍSIMAS GRACIAS!
ABRAZO!
LEO.

Leandro E. Colombo Viña

unread,
Feb 13, 2014, 5:57:59 AM2/13/14
to web2py-...@googlegroups.com
Muchas gracias de nuevo Julio!


El 10 de febrero de 2014, 10:47, isi_jca <juliocesa...@gmail.com> escribió:
Leandro:

En base a las sugerencias de Samuel te mando una versión 3.

Saludos.

El sábado, 8 de febrero de 2014 21:23:23 UTC-3, isi_jca escribió:
Reply all
Reply to author
Forward
0 new messages