[web2py] bootstrap modal and web2py LOAD()

1,962 views
Skip to first unread message

Richard

unread,
Nov 1, 2012, 5:24:35 PM11/1/12
to web...@googlegroups.com
Hello,

Anyone get work bootstrap modal with web2py LOAD() without having the whole page reloaded on embedded form (load component contain a form) submit??

Thanks

Richard

LightDot

unread,
Nov 1, 2012, 8:14:43 PM11/1/12
to
By "the whole page", do you mean the page from where the modal is called or just the contents of the modal itself..?

Anyway, I'm using LOAD() to display a form in a Bootstrap modal, the form submits data, data is processed by a function and a result is displayed in the same modal. I'd have to look at the code but if remember correctly, it was quite straightforward - just needs ajax trap set to true in the LOAD().

I'm using a custom html form in the view, SQLFORM.factory in the controller, the function is called on form.process(...).accepted.

Regards,
Ales

Annet

unread,
Nov 2, 2012, 3:38:37 AM11/2/12
to web...@googlegroups.com
Hi Richard,

Here's how I implemented Bootstrap Modal:

Button in the view:

<a class="btn btn-primary btn-mini" href="{{=URL('event',args=r.id)}}" data-toggle="modal"
 data-target="#eventModal">{{=T("View details")}} &raquo;</a>

At the bottom of the same view:

<script type="text/javascript">
  $("a[data-toggle=modal]").click(function (e) {
    target = $(this).attr('data-target')
    url = $(this).attr('href')
    $(target).load(url);
  })
</script>

<div id="eventModal" class="modal hide fade">
</div> <!-- /modal -->

Kind regards,

Annet

LightDot

unread,
Nov 2, 2012, 6:28:59 AM11/2/12
to web...@googlegroups.com
I simply did (actual functions etc. are stripped out, so some minor detail about displaying the data after it has been processed might be missing):

View:

<div id="some_btn"><a class="btn btn-success btn-mini" data-target="#some_modal" data-toggle="modal"><i class="icon-search icon-white"></i> Open modal</a></div>
       
<div id="some_modal" class="modal hide fade">
           
<div class="modal-header"><button type="button" class="close" data-dismiss="modal">&times;</button>&nbsp;</div>
           
<div class="modal-body">{{=LOAD('controller','somepage.load', ajax=True, ajax_trap=True, user_signature=True)}}</div>
           
<div class="modal-footer">&nbsp;</div>
       
</div>

Controller:

def somepage():
    form
= SQLFORM.factory(
       
Field('somefield'),
       
Field('anotherfield'),
        formname
='some_form',
        formstyle
='bootstrap')
   
if form.process(session=None, formname='some_form').accepted:
        response
.flash = None
       
...do what you need to do...
   
elif form.errors:
        response
.flash = None
       
...do what you need to do...
   
return dict(functionresult=functionresult)

somepage.load:

<form id="some_form_modal" class="form-inline">
   
<div class="input-prepend">
       
<span class="add-on">www.</span>
       
<input name="somefield" type="text" class="input-medium" placeholder="server">
       
<select name="anotherfield" class="span1">...dropdown data...</select>
       
<input type="hidden" name="_formname" value="some_form" />
   
</div>
   
<button type="submit" class="btn btn-success"><i class="icon-search icon-white"></i> ..Submit button txt...</button>
</form>
<div id="some_form_result">
...I'm displaying data processed by a function here...
</div>


I'm not displaying the SQLFORM.factory in the view, since in my case it was more efficient to create a custom form. You could display the SQLFORM.factory or the fully fledged SQLFORM, if this suits your need.

Regards,
Ales

Richard Vézina

unread,
Nov 2, 2012, 9:34:47 AM11/2/12
to web...@googlegroups.com
Hello,

Thanks for you help...

My code look pretty much like the one of LightDot. I will double check for the details.

To your question LightDot, yes I mean the page that contain the load component reload when the form included in the component is submit, since the page that contain the component is also a form. Maybe both form share the same id or name...

I will check my code.

Richard

--
 
 
 

Richard Vézina

unread,
Nov 2, 2012, 10:40:43 AM11/2/12
to web...@googlegroups.com
I think I start to understand what going on...

For a reason that I ignore the form tag of my embedded component form is not present when I use modal, but it is present if I use jQuery .dialog()

Richard

Richard Vézina

unread,
Nov 2, 2012, 11:31:15 AM11/2/12
to web...@googlegroups.com
Can't understand why this code from view is working properly (I mean the LOAD form is complete form input and form tag) :

{{=DIV(DIV(XML('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'),
            XML('<h3 id="modal_eregistry_label">'+'TITRE MODAL TEST'+'</h3>'),
            _class='modal-header'),
            DIV(LOAD(c='ref', f='add_eregistry', args='test_ph_eregistry_id',ajax=True),
                _class='modal-body'),
            _id='modal_eregistry',
            _class='modal hide fade',
            _tabindex='-1',
            _role='dialog',
            **{'_aria-labelledby':'modal_eregistry_label', '_aria-hidden':'true'})}}
{{=A(I(_class='icon-plus'), _href='#modal_eregistry', _role='button', _class='btn', **{'_data-toggle':'modal'})}}

And when I generate it from the class below it not working (form tag of the LOAD component is omitted, but the rest of the form element are present) :

class AutocompleteWidgetSelectOrAddOptionTBootstrap(object):
    _class = 'string'

    def __init__(self, request, field, id_field=None, db=None,
                 orderby=None, limitby=(0,10),
                 keyword='_autocomplete_%(fieldname)s',
                 min_length=2,
                 # -------------------------------------------------------------
                 # From : SelectOrAddOption
                 controller=None, function=None, form_title=None,
                 button_text = None, dialog_width=1000
                 # -------------------------------------------------------------
                 ):
        self.request = request
        self.keyword = keyword % dict(fieldname=field.name)
        self.db = db or field._db
        self.orderby = orderby
        self.limitby = limitby
        self.min_length = min_length
        self.fields=[field]
        if id_field:
            self.is_reference = True
            self.fields.append(id_field)
        else:
            self.is_reference = False
        if hasattr(request,'application'):
            self.url = URL(args=request.args)
            self.callback()
        else:
            self.url = request
        # ----------------------------------------------------------------------
        # From : SelectOrAddOption
        if form_title == None:
            self.form_title = T('Add New')
        else:
            self.form_title = T(form_title)
        if button_text == None:
            self.button_text = T('Add')
        else:
            self.button_text = T(button_text)
        self.dialog_width = dialog_width

        self.controller = controller
        self.function = function
        # ----------------------------------------------------------------------
    def callback(self):
        if self.keyword in self.request.vars:
            field = self.fields[0]
            rows = self.db(field.like(self.request.vars[self.keyword]+'%'))\
                .select(orderby=self.orderby,limitby=self.limitby,*self.fields)
            if rows:
                if self.is_reference:
                    id_field = self.fields[1]
                    raise HTTP(200,SELECT(_id=self.keyword,_class='autocomplete',
                                          _size=len(rows),_multiple=(len(rows)==1),
                                          *[OPTION(s[field.name],_value=s[id_field.name],
                                                   _selected=(k==0)) \
                                                for k,s in enumerate(rows)]).xml())
                else:
                    raise HTTP(200,SELECT(_id=self.keyword,_class='autocomplete',
                                          _size=len(rows),_multiple=(len(rows)==1),
                                          *[OPTION(s[field.name],
                                                   _selected=(k==0)) \
                                                for k,s in enumerate(rows)]).xml())
            else:

                raise HTTP(200,'')
    def __call__(self,field,value,**attributes):
        # ----------------------------------------------------------------------
        # From : SelectOrAddOption
        my_select_id = '%s_%s' % (field._tablename, field.name
        add_args = [my_select_id]
        #create a div that will load the specified controller via ajax
        form_loader_div = DIV(\
            DIV(XML('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'),
            XML('<h3 id="modal_eregistry_label">'+self.form_title+'</h3>'),
                _class='modal-header'),
            DIV(LOAD(c=self.controller, f=self.function, args=add_args,
                ajax=True),
                _class='modal-body', _id=my_select_id+"_dialog-form"),
            _id='modal_eregistry',
            _class='modal hide fade',
            _tabindex='-1',
            _role='dialog',
            **{'_aria-labelledby':'modal_eregistry_label', '_aria-hidden':'true'})
        #generate the "add" button that will appear next the options widget and open our dialog
        activator_button = A(I(_class='icon-plus'), _href='#modal_eregistry', _role='button', _class='btn', **{'_data-toggle':'modal'})

        js = ''#'$("#modal_eregistry").modal({ show: false, keyboard: true, remote: false });'

        jq_script=SCRIPT(js, _type="text/javascript")

        wrapper = DIV(_id=my_select_id+"_adder_wrapper")
        # ----------------------------------------------------------------------
        default = dict(
            _type = 'text',
            value = (not value is None and str(value)) or '',
            )
        attr = StringWidget._attributes(field, default, **attributes)
        div_id = self.keyword+'_div'
        attr['_autocomplete']='off'
        if self.is_reference:
            key2 = self.keyword+'_aux'
            key3 = self.keyword+'_auto'
            attr['_class']='string'
            name = attr['_name']
            if 'requires' in attr: del attr['requires']
            attr['_name'] = key2
            value = attr['value']
            record = self.db(self.fields[1]==value).select(self.fields[0]).first()
            attr['value'] = record and record[self.fields[0].name]
            attr['_onblur']="jQuery('#%(div_id)s').delay(700).fadeOut();" % \
                dict(div_id=div_id,u='F'+self.keyword) # delay(500) is pretty important for "$('#%s').keyup(); $('#%s').blur();" from the add_eregistry function
            attr['_onkeyup'] = "jQuery('#%(key3)s').val('');var e=event.which?event.which:event.keyCode; function %(u)s(){jQuery('#%(id)s').val(jQuery('#%(key)s :selected').text());jQuery('#%(key3)s').val(jQuery('#%(key)s').val())}; if(e==39) %(u)s(); else if(e==40) {if(jQuery('#%(key)s option:selected').next().length)jQuery('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); %(u)s();} else if(e==38) {if(jQuery('#%(key)s option:selected').prev().length)jQuery('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); %(u)s();} else if(jQuery('#%(id)s').val().length>=%(min_length)s) jQuery.get('%(url)s?%(key)s='+escape(jQuery('#%(id)s').val()),function(data){if(data=='')jQuery('#%(key3)s').val('');else{jQuery('#%(id)s').next('.error').hide();jQuery('#%(div_id)s').html(data).show().focus();jQuery('#%(div_id)s select').css('width',jQuery('#%(id)s').css('width'));jQuery('#%(key3)s').val(jQuery('#%(key)s').val());jQuery('#%(key)s').change(%(u)s);jQuery('#%(key)s').click(%(u)s);};}); else jQuery('#%(div_id)s').fadeOut();" % \
                dict(url=self.url,min_length=self.min_length,
                     key=self.keyword,id=attr['_id'],key2=key2,key3=key3,
                     name=name,div_id=div_id,u='F'+self.keyword)
            if self.min_length==0:
                attr['_onfocus'] = attr['_onkeyup']
            wrapper.components.extend([TAG[''](INPUT(**attr),
                                      INPUT(_type='hidden',
                                      _id=key3,
                                      _value=value,
                                      _name=name,
                                      requires=field.requires),
                                      DIV(_id=div_id,
                                      _style='position:absolute;')),
                                      form_loader_div,
                                      activator_button,
                                      jq_script])
            return wrapper
        else:
            attr['_name']=field.name
            attr['_onblur']="jQuery('#%(div_id)s').delay(700).fadeOut();" % \
                dict(div_id=div_id,u='F'+self.keyword) # delay(500) is pretty important for "$('#%s').keyup(); $('#%s').blur();" from the add_eregistry function
            attr['_onkeyup'] = "var e=event.which?event.which:event.keyCode; function %(u)s(){jQuery('#%(id)s').val(jQuery('#%(key)s').val())}; if(e==39) %(u)s(); else if(e==40) {if(jQuery('#%(key)s option:selected').next().length)jQuery('#%(key)s option:selected').attr('selected',null).next().attr('selected','selected'); %(u)s();} else if(e==38) {if(jQuery('#%(key)s option:selected').prev().length)jQuery('#%(key)s option:selected').attr('selected',null).prev().attr('selected','selected'); %(u)s();} else if(jQuery('#%(id)s').val().length>=%(min_length)s) jQuery.get('%(url)s?%(key)s='+escape(jQuery('#%(id)s').val()),function(data){jQuery('#%(id)s').next('.error').hide();jQuery('#%(div_id)s').html(data).show().focus();jQuery('#%(div_id)s select').css('width',jQuery('#%(id)s').css('width'));jQuery('#%(key)s').change(%(u)s);jQuery('#%(key)s').click(%(u)s);}); else jQuery('#%(div_id)s').fadeOut();" % \
                dict(url=self.url,min_length=self.min_length,
                     key=self.keyword,id=attr['_id'],div_id=div_id,u='F'+self.keyword)
            if self.min_length==0:
                attr['_onfocus'] = attr['_onkeyup']
            wrapper.components.extend([TAG[''](INPUT(**attr),
                                      DIV(_id=div_id,
                                      _style='position:absolute;')),
                                      form_loader_div,
                                      activator_button,
                                      jq_script])
            return wrapper

Richard
Reply all
Reply to author
Forward
0 new messages