The id field and what field you want to show as a representation of the id field of the referenced table...
Start by putting the widget class in model file even if it not a good thing to see if you can make it works... In the module I have these imports : from gluon.html import * from gluon.sqlhtml import * from gluon import current from gluon.compileapp import LOAD Which may not be related to the widget class... Richard On Tue, May 5, 2015 at 4:28 PM, LoveWeb2py <atayloru...@gmail.com> wrote: > Hi Richard, > > I'm trying to get this setup, but am receiving an error self.url = > URL(args=request.args)\nNameError: global name \'URL\' is not defined\n'. > I'm wondering if this is because the gluon hasn't been imported yet. > > Also, could you ellaborate more on this? > > > field=db.table.representing_field, > id_field=db.table.id_field, > > id_field should be the foreignkey table if I am not mistaking? > db.table.representing field, and db.table2.id_field (with foreign key) does > that sound right? > > > On Wednesday, April 29, 2015 at 10:04:35 AM UTC-4, Richard wrote: > >> *# 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 <atayl...@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:/ <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.