"Add" button next to "combo box"

149 views
Skip to first unread message

Renato-ES-Brazil

unread,
Oct 2, 2009, 8:41:39 PM10/2/09
to web2py-users
Hi guys!

When the form displays the select with several options from the other
table, using the "is_in_db" configuration, couldn't also to put a
button, for example "ADD NOW", next to it to allows add a new option?

Currently is there this possibility for the CRUD (create and update
forms)?

Iceberg

unread,
Oct 3, 2009, 1:52:00 AM10/3/09
to web2py-users
I've been in same situation as you mentioned. Here is my journey.

Adding a "Add Now" button is easy. You can either customize the form,
or customize the widget, or just use some jquery effect in a way like
this:

def youraction():
form=crud.create(...)
...
return dict(form=DIV(
form,
SCRIPT('''$(document).ready(function() {
$("#your_widgit_id").after(
"<a target='_blank' href='/yourapp/default/addnow'>Add Now</
a>");
});'''),
))

However, I found that after successfully adding a new entry into db,
there is no obvious way to refresh the is_in_db field itself,
providing that I don't want to HARDCODE one more dedicated ajax action
in my already-too-complex controller.

So, my user still have to refresh the whole original page to see the
change after "add now", with a price of losing all his previous input.
Lucky enough that I could arrange the is_in_db field at the first line
of my form, so the waste of input is minimum. In this case, the
benefit of "Add Now" button is not as big as we thought.

If anybody knows a better solution, please give me some tips. Thanks!

Sincerely,
Iceberg

Álvaro Justen [Turicas]

unread,
Oct 4, 2009, 11:14:09 PM10/4/09
to web...@googlegroups.com

You could open a popup with a SQLFORM to create a new register in
other table, with a JavaScript/AJAX to update dropdown's options (and
select option that was created), like Djando admin do.
You could also use a "overlay" to show the form instead of the popup.
See: http://alvarojunior.com/jquery/joverlay/0.7.1/

--
Álvaro Justen
Peta5 - Telecomunicações e Software Livre
21 3021-6001 / 9898-0141
http://www.peta5.com.br/

mdipierro

unread,
Oct 5, 2009, 12:08:29 AM10/5/09
to web2py-users
It would be nice to a widget that does this.

On Oct 4, 10:14 pm, Álvaro Justen [Turicas] <alvarojus...@gmail.com>
wrote:

Renato-ES-Brazil

unread,
Oct 5, 2009, 7:03:15 AM10/5/09
to web2py-users
Cool!

Before I try to do something I really wanted to know if there was
something done by passing a parameter.

Thanks a lot guys!

Renato-ES-Brazil

unread,
Oct 5, 2009, 8:44:31 PM10/5/09
to web2py-users
I am here trying to create a custom widget, inside a class that
extends SQLFORM, but how could I create a custom widget that allow me
to send others parameters besides "field" and "value"?

I would like call the new widget by sending the parameters "control"
and "function". So, inside the function, I would use the values to
create properly the "add" link (url).

I found only a few examples of customization of widget.

Thanks.

mdipierro

unread,
Oct 5, 2009, 9:21:56 PM10/5/09
to web2py-users
you can do something like

class MyWidget:
def __init__(self,**parameters):
self.parameters=parameters
def __call__(self,field,value):
# use self.parameters
return INPUT(_type='text',_name=field.name,_value=value)

db.table.field.widget=MyWidget(parameter1="1",parameter2="2")

Renato-ES-Brazil

unread,
Oct 5, 2009, 9:22:27 PM10/5/09
to web2py-users
I've created a simple code.

In my db_task.py I have the following lines, among others:

from applications.myapp.modules.mywidgets import *

db.main.product.requires=IS_IN_DB(db,db.product.id,db.product.name,
orderby=~db.product.name)
db.main.product.widget = options_with_add_link.widget


And in my module mywidgets.py I have the class:

class options_with_add_link(SQLFORM):
@staticmethod
def widget(field,value,**attr):
select = OptionsWidget.widget(field,value,**attr)
id = "%(tablename)s_%(fieldname)s" %
{"tablename":field._tablename,"fieldname":field.name}
script_add_button = SCRIPT(
"""$(document).ready(function() {
$("#%(id)s").after(
\"<a target='_blank' href=\'%(url)s\'>%(text)s</a>\"
);
}
)""" % {"id" : id,"url":URL
(a="myapp",c=field.name,f="create"),"text":"Add"}
)
return DIV(select, script_add_button)



Notice above, in the line where I create the "add" link, that I call
the "URL" method by passing hard coded values. I don't want it.

mdipierro

unread,
Oct 5, 2009, 9:31:08 PM10/5/09
to web2py-users
I do not think you need to extend SQLFORM to implement this. You just
need a new widget for the reference field. I think.
Not that there is anything worng with extending SQLFORM but I think it
may be more complex that needs to be.

Renato-ES-Brazil

unread,
Oct 5, 2009, 9:41:16 PM10/5/09
to web2py-users
Massimo, I don't believe! The solution is simpler than I thought. :-)
Thanks a lot! :-)

From what I read in the manual I thought I had to extend SQLFORM
manually.

The solution solved my needs, but just to clarify me, how I could
implement the same solution but using a class that extends SQLFORM?

Renato-ES-Brazil

unread,
Oct 12, 2009, 8:46:09 PM10/12/09
to web2py-users
I'm working with this idea again.

Clicking on the link "add" opens a div popup with a form to create the
record. This form is submitted via ajax, but I'm having a problem: the
validation with form.accepts is failing, but the values are in
request.vars.

Seems to be due to SQLFORM put different values for the attributes ID
("tablename_fieldname") and NAME ("fieldname") in the objects.

I've created a form manually and put the same value for attributes
"ID" and "NAME", and it worked.

Any tips?

mdipierro

unread,
Oct 12, 2009, 9:51:48 PM10/12/09
to web2py-users
I am not sure I understand. the values are always in request.vars.
Those values that pass validation they are copied in form.vars.

Renato-ES-Brazil

unread,
Oct 12, 2009, 10:17:04 PM10/12/09
to web2py-users
Massimo,

Sorry, I'll try to explain better...

I know that the values are in request.vars, therefore I made the
observation: "form.accepts" failed even with all the values in
request.vars. :-/

The problem mentioned just occurs when I submit a form, created by
SQLFORM, via ajax.

I think it happens because of "ID" and "NAME" of the html objects are
created with different values when I use SQLFORM.

When I create a form manually with the same values for "ID" and
"NAME", as in the example on page 277 of the manual, it works.

Renato-ES-Brazil

unread,
Oct 13, 2009, 12:17:28 PM10/13/09
to web2py-users
Massimo,

#1. Any idea? :-)

#2. Is there any way of SQLFORM put the same values into the
attributes ID and NAME?

Thadeus Burgess

unread,
Oct 13, 2009, 12:29:20 PM10/13/09
to web...@googlegroups.com
Perhaps its a problem with _formkey?

-Thadeus

Renato-ES-Brazil

unread,
Oct 13, 2009, 5:25:04 PM10/13/09
to web2py-users
Thadeus,

But when I create the form manually it works.
The only difference is that I put the same value into the attributes
ID and NAME.

Thanks.

On 13 out, 13:29, Thadeus Burgess <thade...@thadeusb.com> wrote:
> Perhaps its a problem with _formkey?
>
> -Thadeus
>
> On Tue, Oct 13, 2009 at 11:17 AM, Renato-ES-Brazil <caliari.ren...@gmail.com

Thadeus Burgess

unread,
Oct 13, 2009, 5:38:52 PM10/13/09
to web...@googlegroups.com
So basically, you have a form created with SQLFORM, then there is an add button, when you click it, you can add new records, then ajax returns and you append the new options to the form?

So the form fails only if you add new?

Is this the correct understanding of the problem?

If so, I believe it might have something to do with _formkey and session storing what the form is expecting?

-Thadeus

Renato-ES-Brazil

unread,
Oct 13, 2009, 6:24:43 PM10/13/09
to web2py-users
The form fails in any attempt to add new record. :-(

The form.accepts always fails because the method isn't able to find
the values from the required fields, even they being filled out and to
be in the request.vars properly.

I notice that it happens because the "ID" and "NAME" attributes
created by SQLFORM had different values. For instance:
<input class="string" id="product_name" name="name" type="text"
value="" />

If I create a form manually with the same value for "ID" and "NAME"
attributes, the validation works properly and the record is saved.

Below is what I'm trying to do in a controller (leaving aside the
module and the view):

************************************
def create_popup():
script_submit = SCRIPT("""
jQuery('#%(form)s').submit(function(){
ajax('%(url_ajax)s',['%(list_fields)s'],'message');
return false;
});
""" % {"form":"form_test",
"url_ajax":URL(r=request,f='validate_popup'),
"list_fields":"','".join([field for field in
db.product.fields
if db.product[field].writable
and db.product[field].readable
and (field != "id") ])}
)

form = SQLFORM(db.product, _enctype=None, _id=form_name,
_action=None, _method=None)
return dict(form=form,script_submit=script_submit)




def validate_popup():
form = SQLFORM(db.product)
if form.accepts(request.vars,formname="form_test"):
return DIV("Product successfully registered!")
elif form.errors:
return TABLE(*[TR(k, v) for k, v in form.errors.items()])

************************************



Thanks!

Renato-ES-Brazil

unread,
Oct 13, 2009, 7:01:03 PM10/13/09
to web2py-users
Fixing:
The code that I posted had a error because I'd edited manually here.
The error was:
"_id=form_name" instead of "_id="form_test". See below:

>     form = SQLFORM(db.product, _enctype=None, _id=form_name,
> _action=None, _method=None)

The correct line is:
form = SQLFORM(db.product, _enctype=None, _id="form_test",
_action=None, _method=None)

mr.freeze

unread,
Oct 13, 2009, 8:30:12 PM10/13/09
to web2py-users
There are a couple of problems I think:

There is a hidden field called "product_create" that needs to be sent
back too:
<input type="hidden" value="product_create" name="_formname"/>

The built in ajax function explicitly grabs fields by ID which won't
work for you since it will send request.vars.product_name instead of
request.vars.name and won't grab the hidden field. Try using
jQuery.ajax and the serialize function to grab the data:

def create_popup():
script_submit = SCRIPT("""jQuery('#%(form)s').submit(function(){
jQuery.ajax({
type: "POST",
url: "%(url_ajax)s",
data: jQuery("#form_test").serialize(),
success: function(msg){jQuery('#message').html(msg);} });
return false;
});""" % {"form":"form_test", "url_ajax":URL
(r=request,f='validate_popup')} )
form = SQLFORM(db.product, _enctype=None,
_id="form_test",_action=None, _method=None)
return dict(form=form,script_submit=script_submit,message=DIV
(_id="message"))

def validate_popup():
form = SQLFORM(db.product)
if form.accepts(request.vars):
return DIV("Product successfully registered!")
elif form.errors:
return TABLE(*[TR(k, v) for k, v in form.errors.items()])
else: return DIV("Nope")

Hope that helps.

Renato-ES-Brazil

unread,
Oct 13, 2009, 8:55:27 PM10/13/09
to web2py-users
mr.freeze,

**************
It worked! Thank you very much!!! :-)
**************



Doubt:
#1 I don't understand very well about the hidden field
"product_create". Could you explain?
Note: I've not used it in my new code.

mr.freeze

unread,
Oct 13, 2009, 9:04:38 PM10/13/09
to web2py-users
It's the form name. You may not need it. _formname is necessary for
pages that contain and process multiple forms. It is added to the
form during form.accepts along with _formkey to prevent double
submission. More info on page 201 (labeled 185) in the manual. Glad
it worked!

In general, it is best to avoid the web2py_ajax.html ajax function for
anything complicated. It is a simple helper to get people started but
has several limitations.

Renato-ES-Brazil

unread,
Oct 13, 2009, 9:13:12 PM10/13/09
to web2py-users
Now, I got it! Thanks! :-)

Markus Schmitz

unread,
Oct 14, 2009, 6:20:35 AM10/14/09
to web2py-users
Hi Renato,

after this long and painfull journey could you post in a single
comprehensive way, what you need to do to get the Add-Button working?
I am sure, several of us need something quite similar.
Maybe Massimo could even turn this into an howto on the FAQ?

Regards

Markus

Renato-ES-Brazil

unread,
Oct 14, 2009, 7:24:17 AM10/14/09
to web2py-users
Hi Markus!

I'm still working in some details for this functionality in my
'available times':

- I need to reload the "select" object to show the new option
registered.

- I would like to improve the structure of the code and files where
possible in order to be easy to implement. Currently has a module with
a widget and a view called "popup.html" as the base.

For each field I wish to implement the "Add" link, I put this widget
on my configuration model.

For example, I wanted to put the link "add" next to the "Product"
combobox So, I informed the widget on this field, and furthermore I
had to declare two methods in the Product controller just call generic
methods that are within my module (create_popup and validate_popup). I
also created a View for the Product popup, that shows the form and
insert a jquery script. The view page extends the page "popup.html"
which is the page that contains some properties for the jquery popup
appears properly.

Thadeus Burgess

unread,
Oct 14, 2009, 11:42:08 AM10/14/09
to web...@googlegroups.com
Write a web2pyslice when you get it hashed out!

-Thadeus

Renato-ES-Brazil

unread,
Oct 15, 2009, 8:32:21 PM10/15/09
to web2py-users
Hi guys!

Another problem found:
- The "form.accepts" fails when I trying submit the form with the
links "add".

Some lines shown in the log:
if form.accepts(request.vars, session):
File "/home/renato/Desenvolvimento/web2py/gluon/sqlhtml.py", line
777, in accepts
self.trows[fieldname][1][0].errors = self.errors
AttributeError: 'tuple' object has no attribute 'errors'



When web2py get the self.trows[fieldname][1], actually, now, it's
taking two objects (the select and the "add" link):
<td>(&lt;gluon.html.SELECT object at 0xa0f41ec&gt;, ' ',
&lt;gluon.html.A object at 0xa100a6c&gt;)</td>




Any tip?

Renato-ES-Brazil

unread,
Oct 15, 2009, 8:39:58 PM10/15/09
to web2py-users
I'll to try do it. :-)

On 14 out, 12:42, Thadeus Burgess <thade...@thadeusb.com> wrote:
> Write a web2pyslice when you get it hashed out!
>
> -Thadeus
>
> On Wed, Oct 14, 2009 at 6:24 AM, Renato-ES-Brazil
> <caliari.ren...@gmail.com>wrote:

Renato-ES-Brazil

unread,
Oct 16, 2009, 2:53:25 PM10/16/09
to web2py-users
Any tips? What could I do to "form.accepts" to get just the first
object (SELECT) and not a tuple (SELECT and A)?

Do I have to remove the A object ("add" link) from the <TD> where is
the SELECT? :-/

Thanks.

Does it happens because "form.accepts" trying get some attributes,
like "errors", from the "add" links?

Renato-ES-Brazil

unread,
Oct 16, 2009, 2:56:38 PM10/16/09
to web2py-users
Please, ignore the last paragraph after the word "Thanks" in the last
message.
So, fixing:

Any tips? What could I do to "form.accepts" to get just the first
object (SELECT) and not a tuple (SELECT and A)?

Do I have to remove the A object ("add" link) from the <TD> where is
the SELECT? :-/

Thanks.


mr.freeze

unread,
Oct 16, 2009, 3:24:01 PM10/16/09
to web2py-users
Is the link inside the form? If so, try moving it outside and see if
it still fails.

Renato-ES-Brazil

unread,
Oct 16, 2009, 6:27:40 PM10/16/09
to web2py-users
mr.freeze,

Yes, the link is inside the form. Each "add" link is next to your own
"select" (combo box) object. The "add" link is created by a widget set
in my model, hence it is rendered by SQLFORM inside the form.

Renato-ES-Brazil

unread,
Oct 17, 2009, 2:20:23 PM10/17/09
to web2py-users
I solved this problem. Now my widget returns the SELECT (combo box)
object and the "add" link inside a DIV object. So, the form.accepts
reads just one object (the DIV) from the <TD>, working properly.

Now, the return of my widget is as follows:
return DIV(select, " ", add_link)

Renato-ES-Brazil

unread,
Oct 17, 2009, 3:19:04 PM10/17/09
to web2py-users
Guys,

I added the widget in web2pyslices.com. Following url:
http://www.web2pyslices.com/main/slices/take_slice/11

Please let me know the problems and feel free to improve it.
Reply all
Reply to author
Forward
0 new messages