*# In a modules :* class AutocompleteWidgetSelectOrAddOption(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, # ------------------------------------------------------------- placeholder=None ): 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] self.placeholder = placeholder 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 is None: self.form_title = current.T('Add New') else: self.form_title = current.T(form_title) if button_text is None: self.button_text = current.T('Add') else: self.button_text = current.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) # 'test_ph_eregistry_id' #select_widget.attributes.get('_id', None) add_args = [my_select_id] # create a div that will load the specified controller via ajax # form_loader_div = DIV(LOAD(c=self.controller, f=self.function, args=add_args, ajax=True), # _id=my_select_id + "_dialog-form", _title=self.form_title) form_loader_div = DIV(DIV(BUTTON('x', _type='button', _class='close', **{'_data-dismiss': 'modal', '_aria-hidden': 'true'}), H3(self.form_title, _id='myModalLabel'), _class='modal-header'), DIV(LOAD(c=self.controller, f=self.function, args=add_args, ajax=True, ajax_trap=True), _class='modal-body'), _id=my_select_id + "_modal-form", _class='modal hide fade', **{'_tabindex': '-1', '_role': 'dialog', '_aria-labelledby': 'myModalLabel', '_aria-hidden': 'true'}) # generate the "add" button that will appear next the options widget and open our modal activator_button = A(I(_class='icon-plus-sign icon-2x'), _id=my_select_id+"_option_add_trigger", _class='add-and-select-button') # create javascript for creating and opening the dialog # js = '$("#%s_dialog-form").dialog({' \ # ' autoOpen: false,' \ # ' show: "fade",' \ # ' hide: "fade",' \ # ' width: %s' \ # ' });' % (my_select_id, self.dialog_width) js = '$("#%s_modal-form").modal({ backdrop: true, keyboard: true, show: false });' % (my_select_id) # js += '$("#%s_option_add_trigger").click(function() {' \ # ' $("#%s_dialog-form").dialog("open");' \ # ' return false;' \ # ' }); ' % (my_select_id, my_select_id) js += '$("#%s_option_add_trigger").click(function() ' \ '{ $("#%s_modal-form").modal("show"); return false; }); ' % (my_select_id, my_select_id) # decorate our activator button for good measure js += '$(function() {' \ ' $("#%s_option_add_trigger").button({' \ ' text: true,' \ ' icons: {' \ ' primary: "ui-icon-circle-plus"' \ ' }' \ ' });' \ '});' % (my_select_id) js += '$(function() { ' \ ' $( "#%s_option_add_trigger" ).css("margin-left", "+=5"); ' \ '});' % (my_select_id) js += '$("#{modal_id}").appendTo("body");'.format(modal_id=my_select_id + "_modal-form") # jQuery .appendTo() move modal div in body to avoid nested form which are not allow in HTML js = """$(document).ready(function() { %s });""" % js 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, _placeholder=self.placeholder, **attributes) div_id = self.keyword+'_div' attr['_autocomplete'] = 'off' if self.is_reference: key2 = self.keyword+'_aux' key3 = self.keyword+'_auto' # ----------------------------------------------------------------------------- # find the longest record and set input size attribute accordingly length = self.fields[0].len() longest_record_length = len(self.db().select(self.fields[0], orderby=~length, limitby=(0, 1)).first()[self.fields[0].name]) attr['_size'] = int(longest_record_length * 1.20) # 20% wider field width # ----------------------------------------------------------------------------- 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'] = "$('#%(div_id)s').delay(1000).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'] = \ "$('#%(key3)s').val('');" \ "var e = event.which?event.which:event.keyCode;" \ "function %(u)s() {" \ " $('#%(id)s').val($('#%(key)s :selected').text());" \ " $('#%(key3)s').val($('#%(key)s').val())" \ "};" \ "if (e == 39) %(u)s();" \ "else if (e == 40) {" \ " if ($('#%(key)s option:selected').next().length)" \ " $('#%(key)s option:selected').attr('selected', null).next().attr('selected', 'selected'); %(u)s();" \ "} else if (e == 38) {" \ " if ($('#%(key)s option:selected').prev().length)" \ " $('#%(key)s option:selected').attr('selected', null).prev().attr('selected', 'selected'); %(u)s();" \ "} else if ($('#%(id)s').val().length >= %(min_length)s)" \ " $.get('%(url)s?%(key)s=' + encodeURI($('#%(id)s').val()), function(data) {" \ " if (data == '')" \ " $('#%(key3)s').val('');" \ " else {" \ " $('#%(id)s').next('.error').hide();" \ " $('#%(div_id)s').html(data).show().focus();" \ " $('#%(div_id)s select').css('width', $('#%(id)s').css('width'));" \ " $('#%(key3)s').val($('#%(key)s').val());" \ " $('#%(key)s').change( %(u)s);" \ " $('#%(key)s').click( %(u)s);" \ " };" \ " });" \ "else $('#%(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'] = "$('#%(div_id)s').delay(1000).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() {" \ " $('#%(id)s').val($('#%(key)s').val())" \ "};" \ "if (e == 39) %(u)s();" \ "else if (e == 40) {" \ " if ($('#%(key)s option:selected').next().length)" \ " $('#%(key)s option:selected').attr('selected', null).next().attr('selected', 'selected'); %(u)s();" \ "} else if (e == 38) {" \ " if ($('#%(key)s option:selected').prev().length) $('#%(key)s option:selected').attr('selected', null).prev().attr('selected', 'selected'); %(u)s();" \ "} else if ($('#%(id)s').val().length >= %(min_length)s) $.get('%(url)s?%(key)s=' + encodeURI($('#%(id)s').val()), function(data) {" \ " $('#%(id)s').next('.error').hide();" \ " $('#%(div_id)s').html(data).show().focus();" \ " $('#%(div_id)s select').css('width', $('#%(id)s').css('width'));" \ " $('#%(key)s').change( %(u)s);" \ " $('#%(key)s').click( %(u)s);" \ "});" \ "else $('#%(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 # In a model (a model file which is already call before you set your widget...) from a_widget import AutocompleteWidgetSelectOrAddOption *# In your controller * def add_function(): """ Modal form for adding element """ buttons = [TAG.button((I('', _class='icon-ok icon-large icon-white'), CAT(' '), STRONG(T('Add'))), _type='submit', _class='btn btn-small btn-primary', _id='add_button_id', _name='add_button', )] form = SQLFORM(db.table, buttons=buttons, formstyle=formstyle, separator=separator) response.js = '$(document).ready(function(){ $(".input_wrapper").has(".error").addClass("inputError"); ' \ '$(".w2p_fw").has(".error").addClass("control-group error"); ' \ '$(".w2p_fw").each(function(){ $(this).find(".error_wrapper").appendTo(this); }); });' response.js += '$(document).ready(function(){ $("textarea").elastic(); });' response.js += '$(document).ready(function () { $("[rel=tooltip]").tooltip(); });' if form.process(formname='add_form').accepted: response.flash = T("Added") target = request.args(0) # close modal response.js = '$("#{target}_modal-form").modal("hide");'.format(target=target) # update the select options response.js += """$("#{target}").append( "<option value='{new_id}'> {new_id} </option>");""".format(target=target, new_id= form.vars.id) # select newly added option response.js += """$("#{target}").val("{new_exp_num}"); $('#{target}').keyup(); $('#{target}').blur();""".format(target=target, new_exp_num=form.vars.exp_num) elif form.errors: response.flash = '' else: response.flash = '' return dict(form=form) *# Then you set the widget to your field * widget=AutocompleteWidgetSelectOrAddOption( request=request, field=db.table.representing_field, id_field=db.table.id_field, limitby=(0, 10), # your pref min_length=6, # your pref form_title=T('Add new element'), controller="ref", function="add_function", # Name of your add_function() button_text=T('Add new'), placeholder=T('Start typing...')) Give feedback here... You may consider to try it first in a dummy app so you can share it here in case you have some difficulties to set it up... It will be easier to help you that way, once you will have understand all the sensitive part you will be able to set it up in you prod app rapidly... Richard On Tue, Apr 28, 2015 at 7:04 PM, LoveWeb2py <atayloru...@gmail.com> wrote: > I'd love to see it, Richard! I'm banging my head against the wall with > this other method. > > On Tuesday, April 28, 2015 at 6:58:25 PM UTC-4, Richard wrote: >> >> My own mix of SELECT_OR_ADD_OPTION() widget and web2py >> SQLFORM.widget.autocomplete... >> >> As wrote above I can share the code here... >> >> Richard >> >> On Tue, Apr 28, 2015 at 5:06 PM, LoveWeb2py <atayl...@gmail.com> wrote: >> >>> What do you use as a replacement? >>> >>> On Tuesday, April 28, 2015 at 4:59:32 PM UTC-4, Richard wrote: >>>> >>>> in view in script tag is a good place for start... just make sure you >>>> have the rigth id for you modal main div... In my case modal_id was coming >>>> from an .fromat(modal_id='id')... >>>> >>>> But I don't recall the exact way this tutorial was doing and I was just >>>> exposing to 2 generals reasons why form into modal won't submit >>>> correctly... In my case my widget was appending my modal with a LOAD >>>> component inside a form of the so the load form has to be put outside the >>>> main form... >>>> >>>> I try the ressource you are using and give up because it was not full >>>> fill all my requirement... >>>> >>>> Richard >>>> >>>> On Tue, Apr 28, 2015 at 4:54 PM, LoveWeb2py <atayl...@gmail.com> wrote: >>>> >>>>> This is what I'm using in my layout: >>>>> >>>>> >>>>> $(function() { >>>>> $("td.w2p_fc").each(function (){ >>>>> var comment = $(this).html(); >>>>> if (comment){ >>>>> $(this).html('<div><i class="icon info icon-info-sign"></i></div>'); >>>>> $(this).children('div').attr('title',comment); >>>>> $(this).children('div').tooltip({ placement : 'right', >>>>> html : true, >>>>> trigger : 'click' }); >>>>> } >>>>> }); >>>>> }); >>>>> >>>>> This makes the comment field available as an "Information Icon" >>>>> >>>>> When I use the modal class referenced in the link it works great, the >>>>> problem is nothing stores because the form can't process properly. I'm >>>>> struggling to solve that last piece of the puzzle. >>>>> >>>>> When I >>>>> >>>>> >>>>> >>>>> On Tuesday, April 28, 2015 at 4:50:34 PM UTC-4, LoveWeb2py wrote: >>>>>> >>>>>> Thank you, Richard. Where do I put $("#{modal_id}").appendTo(" >>>>>> body"); >>>>>> >>>>>> Could I just put that in the HTML file? Something like... >>>>>> >>>>>> <script> >>>>>> $("#{modal_id}").appendTo(" >>>>>> body"); >>>>>> </script> >>>>>> >>>>>> I tried hardcoding the div_id of my modal into your code, but it >>>>>> didn't work. The database doesn't update properly with the correct >>>>>> foreign >>>>>> key. I also have some date value fields and the calendar.js doesn't pop >>>>>> down so I'm thinking this has something to do with >>>>>> http://linuxapuntes.blogspot.com.ar/2013/03/plugin-modal-bootstrap-web2py.html >>>>>> >>>>>> Do you have an example of where you'd put the appendTo ? >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> On Tuesday, April 28, 2015 at 1:04:57 PM UTC-4, Richard wrote: >>>>>>> >>>>>>> There is different issue when embed for into a bootstrap 2.3.2 (at >>>>>>> least)... One that I found were that <form> tag get ripped off... The >>>>>>> other >>>>>>> depend of the way the modal form compoenent is included into the main >>>>>>> form... Depending how the widget is write the extra are embed beside the >>>>>>> original input field which don't work in case of a <form> tag since html >>>>>>> <form> can't be nested... Modal don't offer any convenient support à >>>>>>> this >>>>>>> level and you have to manage this by yourself... But it is easy, you >>>>>>> just >>>>>>> need to use jquery .appendTo() : >>>>>>> >>>>>>> Like that : $("#{modal_id}").appendTo("body"); >>>>>>> >>>>>>> And extract your component modal form which is nested into the main >>>>>>> page form and append it to the body instead... >>>>>>> >>>>>>> This is basically what jQuery Dialog is doing out of the box which >>>>>>> boostrap modal don't that make the usage of modal with component in >>>>>>> web2py >>>>>>> so difficult... >>>>>>> >>>>>>> :) >>>>>>> >>>>>>> Richard >>>>>>> >>>>>>> >>>>>>> On Tue, Apr 28, 2015 at 12:40 PM, LoveWeb2py <atayl...@gmail.com> >>>>>>> wrote: >>>>>>> >>>>>>>> Richard, >>>>>>>> >>>>>>>> This is working great. >>>>>>>> http://linuxapuntes.blogspot.com.ar/2013/03/plugin-modal-bootstrap-web2py.html >>>>>>>> >>>>>>>> I currently use it like this: >>>>>>>> >>>>>>>> def my_controller(): >>>>>>>> from modalplugins Import Modal >>>>>>>> field = db.mytable.field >>>>>>>> modal = Modal(field, ' Add', 'Add area','Area') >>>>>>>> db.mytable.field.comment = modal.create() >>>>>>>> grid=SQLFORM.smartgrid(db.my_other_table) >>>>>>>> formModal = modal.formModal() >>>>>>>> return(grid=grid, formModal=formModal) >>>>>>>> >>>>>>>> The problem I am having now is that I can't process the modal. Do >>>>>>>> you have any thoughts on how to do this? >>>>>>>> >>>>>>>> On Friday, April 17, 2015 at 9:50:15 AM UTC-4, Richard wrote: >>>>>>>>> >>>>>>>>> 'reference tablename' = 1 to many >>>>>>>>> 'list:reference tablename' = "many to many" it denormalised that >>>>>>>>> why I put it between double quotes >>>>>>>>> >>>>>>>>> Richard >>>>>>>>> >>>>>>>>> On Thu, Apr 16, 2015 at 5:13 PM, LoveWeb2py <atayl...@gmail.com> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> Richard, >>>>>>>>>> >>>>>>>>>> I did want to have a foreign key for info_about_field1. I guess I >>>>>>>>>> could do a reference field1 ? >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Thursday, April 16, 2015 at 3:02:51 PM UTC-4, Richard wrote: >>>>>>>>>>> >>>>>>>>>>> There is no relation between both tables... You can embed 2 >>>>>>>>>>> forms as component (LOAD()) >>>>>>>>>>> >>>>>>>>>>> if you were having list:reference type field it is differents >>>>>>>>>>> and you have to question yourself if you are not better to have >>>>>>>>>>> something >>>>>>>>>>> like SELECT_OR_ADD_OPTION() or even better >>>>>>>>>>> AutocompleteSelectOrAddOption() >>>>>>>>>>> widget... I recently update my old AutocompleteSelectOrAddOption() >>>>>>>>>>> widget (not finish yet) in order to move from jquery ui dialog to >>>>>>>>>>> bootstrap >>>>>>>>>>> modal... I will publish a web2py slice when done. >>>>>>>>>>> >>>>>>>>>>> Just ask if it interest you I can publish preview here... >>>>>>>>>>> >>>>>>>>>>> Richard >>>>>>>>>>> >>>>>>>>>>> On Thu, Apr 16, 2015 at 2:08 PM, LoveWeb2py <atayl...@gmail.com> >>>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>>> Hello, >>>>>>>>>>>> >>>>>>>>>>>> I'd like to have two SQLFORMs right next to each other. >>>>>>>>>>>> >>>>>>>>>>>> The second SQLFORM is just going to be linked to the field in >>>>>>>>>>>> table 1, but will be used so the student can make additional >>>>>>>>>>>> comments about >>>>>>>>>>>> a field. Model will look like this: >>>>>>>>>>>> >>>>>>>>>>>> db.define_table('main_table', >>>>>>>>>>>> Field('field1','string'), >>>>>>>>>>>> Field('field2','string'), >>>>>>>>>>>> migrate=False) >>>>>>>>>>>> >>>>>>>>>>>> db.define_table('second_table', >>>>>>>>>>>> Field('info_about_field1','list:string'), >>>>>>>>>>>> Field('info_about_field2','list:string') >>>>>>>>>>>> migrate=False) >>>>>>>>>>>> >>>>>>>>>>>> My question is... is it possible to have the second_table as a >>>>>>>>>>>> link underneath the main_table field. I want to have a modal pop >>>>>>>>>>>> up so they >>>>>>>>>>>> can enter additional information about the field >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> -- >>>>>>>>>>>> Resources: >>>>>>>>>>>> - http://web2py.com >>>>>>>>>>>> - http://web2py.com/book (Documentation) >>>>>>>>>>>> - http://github.com/web2py/web2py (Source code) >>>>>>>>>>>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>>>>>>>>>>> --- >>>>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>>>> Google Groups "web2py-users" group. >>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from >>>>>>>>>>>> it, send an email to web2py+un...@googlegroups.com. >>>>>>>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>> Resources: >>>>>>>>>> - http://web2py.com >>>>>>>>>> - http://web2py.com/book (Documentation) >>>>>>>>>> - http://github.com/web2py/web2py (Source code) >>>>>>>>>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>>>>>>>>> --- >>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>> Google Groups "web2py-users" group. >>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>>> send an email to web2py+un...@googlegroups.com. >>>>>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>> Resources: >>>>>>>> - http://web2py.com >>>>>>>> - http://web2py.com/book (Documentation) >>>>>>>> - http://github.com/web2py/web2py (Source code) >>>>>>>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>>>>>>> --- >>>>>>>> You received this message because you are subscribed to the Google >>>>>>>> Groups "web2py-users" group. >>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>> send an email to web2py+un...@googlegroups.com. >>>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>>> >>>>>>> >>>>>>> -- >>>>> Resources: >>>>> - http://web2py.com >>>>> - http://web2py.com/book (Documentation) >>>>> - http://github.com/web2py/web2py (Source code) >>>>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>>>> --- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "web2py-users" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to web2py+un...@googlegroups.com. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> -- >>> Resources: >>> - http://web2py.com >>> - http://web2py.com/book (Documentation) >>> - http://github.com/web2py/web2py (Source code) >>> - https://code.google.com/p/web2py/issues/list (Report Issues) >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "web2py-users" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to web2py+un...@googlegroups.com. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> -- > Resources: > - http://web2py.com > - http://web2py.com/book (Documentation) > - http://github.com/web2py/web2py (Source code) > - https://code.google.com/p/web2py/issues/list (Report Issues) > --- > You received this message because you are subscribed to the Google Groups > "web2py-users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to web2py+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.