If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

Steps:

1) Put the jquery.jmpopups-0.5.1 in the static folder. It can be found at http://code.google.com/p/jmpopups/

2) Put the following lines into the web2py_ajax.html, BEFORE of the <script type="text/javascript"> tag:

<script src="{{=URL(r=request,c='static',f='jquery.jmpopups-0.5.1.js')}}" type="text/javascript"></script>

3) Put the following lines into the web2py_ajax.html, INSIDE the <script type="text/javascript"> tag:

$.setupJMPopups({
    screenLockerBackground: "#003366",
    screenLockerOpacity: "0.7"
});

function openAjaxPopup(name_popup, width, url) {
    $.openPopupLayer({
        name: name_popup,
        width: width,
        url: url
    });
}

4) Put the module widgetAddLink.py in the modules folder. The contents of the file is below:

#!/usr/bin/env python 
# coding: utf8 
from gluon.html import *
from gluon.http import *
from gluon.validators import *
from gluon.sqlhtml import *
# request, response, session, cache, T, db(s) 
# must be passed and cannot be imported!

class OPTIONS_WITH_ADD_LINK:
    def __init__(self,**parameters):
         self.parameters=parameters
    def __del__(self): pass
    def __call__(self,field,value):
        """
        example::
            db.main.product.widget = OPTIONS_WITH_ADD_LINK(T=T, r=request, c="product")

        When the form is rendered it shows a dropbox and a "add" link
        """        

        # Create a SELECT object
        select = OptionsWidget.widget(field,value)

        # Get the parameters
        request = self.parameters["r"] 
        a = request.application
        c = self.parameters["c"]
        T = self.parameters["T"]
        f = self.parameters["f"] or None #new paremeter either None or the name of the field to use           

        requires = select.attributes["requires"]

        # If is not the "IS_IN_DB" validator then can be that the line below fails 
        # because the requires can't have "ks" object        
        try:
            # Get the field name from the foreign table from validator IS_IN_DB
            if f is None:
                field_name = requires.ks[0]
            else:
                field_name = f #use the one we specified (because there was no "ks" object)
        except AttributeError:
            return select
        else:
            # Get the id from the SELECT object that allows adding an option
            select_id = select.attributes.get('_id', None)

            id = "%(tablename)s_%(fieldname)s" % {"tablename":field._tablename,
                "fieldname":field.name}
            popup_id = "popup_%s" % id
            width = 700

            # Build the URL responsible for opening a popup window in the same screen
            url= URL(r=request, c=c, f="create_popup",
                vars=dict(title_name=field.name,field_name=field_name, 
                        select_id=select_id))


            # Create the script that add the "Add" link after the SELECT object
            add_link = A(T("Add"), 
                                    _id="add_%s" % id,
                                    _name="add_%s" % id,
                                    _href="#",
                                    _onclick=("openAjaxPopup('%(name)s',%(width)d,'%(url)s')"\
                                        % {"id": id, "name":popup_id, "width":width, "url":url}),
                                    _title="Add")

            return DIV(select, " ", add_link)

def create_popup(request, table):
    """
    Create a popup with a form to register a new record
    """

    select_id = request.vars.select_id
    form_name = "form_%(name)s" % {"name":select_id}
    field_name = request.vars.field_name

    url_ajax = URL(r=request,f='validate_popup', 
        vars=dict(form_name=form_name, select_id=select_id, field_name=field_name))

    # Build the script responsible for submiting the form via ajax
    script_submit = SCRIPT("""jQuery('#%(form)s').submit(function(){ 
        jQuery.ajax({
                 type: "POST",
                 url: "%(url_ajax)s",
                 data: jQuery("#%(form)s").serialize(),
                 success: function(msg){jQuery('#message').html(msg);} });
        return false;
        });""" %  {"form":form_name, "url_ajax":url_ajax}  )

    form = SQLFORM(table, _enctype=None, _id=form_name,_action=None, _method=None)
    return dict(form=form,script_submit=script_submit,message=DIV(_id="message")) 

def validate_popup(request, table):
    """
    Validate the data from popup 
    """

    select_id = request.vars.select_id or None
    field_name = request.vars.field_name or None
    field_value = request.vars["%s" % field_name]

    form = SQLFORM(table)

    if form.accepts(request.vars,formname=None):
        script = "$.closePopupLayer();"
        if select_id:
            script_add_option = """$("#%s").append("<option value='%s'>%s</option>");""" \
                % (select_id, form.vars.id, field_value)
            script_select_option = """$("#%s").val("%s");""" % (select_id, field_value)
        return SCRIPT(script,script_add_option,script_select_option)
    elif form.errors:
        return DIV(TABLE(*[TR("%s %s" % (k,v)) for k, v in form.errors.items()]))

5) Put the popup.html in the views folder. The contents of the file is below:

<style type="text/css" media="screen">
    .popup {background:#FFF; border:1px solid #333; padding:1px;}
    .popup-header {height:24px; padding:7px; background:url("bgr_popup_header.jpg") repeat-x;}
    .popup-header h2 {margin:0; padding:0; font-size:18px; float:left;}
    .popup-header .close-link {float:right; font-size:11px;}
    .popup-body {padding:10px;}
</style>
<div class="popup">
    <div class="popup-header">
        <h2>{{=T("Create a %(name)s", dict(name=request.vars.title_name)) }}</h2>
        <a href="javascript:;" onclick="$.closePopupLayer()" title="Close" class="close-link">{{=T("Close")}}</a>
        <br clear="both" />
    </div>
    <div class="popup-body">
        {{=message}}
        {{=form}}
        {{=script_submit}}
    </div>
</div>

6) Import the module in your model (maybe db.py):

exec('from applications.%s.modules.widgetAddLink import *' % request.application)

7) Add this widget to some field that uses the validator IS_IN_DB. Example:

db.main.product.requires = IS_IN_DB(db,db.product.id,db.product.name)
db.main.product.widget = OPTIONS_WITH_ADD_LINK(T=T, r=request, c="product")

Note: The OPTIONS_WITH_ADD_LINK requires three arguments:

a) T object (the object T is the language translator)

b) Request

c) and the name of the controller responsible for add a new register to the field in the left side

d) f (field) is optional.

8) Import the module in the controller specified above, in the widget configuration (e.g. product.py):

exec('import applications.%s.modules.widgetAddLink as popup' % request.application)

9) Add the following two methods into this controller:

def create_popup():
    response.view='popup.html'
    return popup.create_popup(request, db.tablename)

def validate_popup():
    return popup.validate_popup(request, db.tablename)

Note: Replace db.tablename to the desired table. Example: db.product

Ready! This should work.


Issues known:

1) The record is added at the end of the list in the combo box. The widget does not reload the combo box object to sort it properly, just adds an item via jquery.

Related slices

Comments (14)

  • Login to post



  • 0
    matclab 14 years ago
    In fact, the script is send as expected. The problem is that the validate_popup function does not get the name of the file that should have been uploaded (and my guess is that no file where uploaded by using the popup window....). I'll investigate more and keep you informed.

  • 0
    matclab 14 years ago
    Hello, This slice looks nice. I still have some difficulties to make it working. The pop-up pops-up as wanted, but the submit button is inoperant. If I add
     print res['script_submit']
    
    In create_popup() I get on stdout :
    
    
    Which looks ok, but still no submit url in the "form_card_file" form (as seen with firebug).... Do you have any clue ?

  • 0
    renatocaliari 15 years ago
    Sophie, It would needs some modification in this widget.

  • 0
    sophie 15 years ago
    This is using the SQLFORM. What can i do if i want to add this link through the controller? I am creating the table in the controller, i think i have to put the widget here, but i dont know how. My controlles is this: form=FORM(TABLE( TD("Caracteristica"), TD(SELECT(_name="caracteristica", *[OPTION(x.Caracteristica.nCaracteristica +' - '+ x.TipoCaracteristica.nTipoCaracteristica,_value=x.Caracteristica.id) for x in db((db.Caracteristica.idTipoCaracteristica==db.TipoCaracteristica.id)&\ (db.Caracteristica.id.belongs(lista))).select(orderby=db.Caracteristica.nCaracteristica)])), TD("Descripcion"),INPUT(_type='text',_name="descripcion"), INPUT(_type='submit',_value='Submit'))) if form.accepts(request.vars, session): if not form.vars.caracteristica=="": db.CaracteristicaCientifico.insert(nCaracteristicaCientifico=form.vars.descripcion, idCaracteristica=form.vars.caracteristica,idCientifico=session.idPrincipal) redirect(URL(r=request, c='cientifico', f='insert', args=["db","CaracteristicaCientifico"])) else: form.errors.caracteristica ='Seleccionar un registro'

  • 0
    renatocaliari 15 years ago
    Thanks mr.freeze!

  • 0
    renatocaliari 15 years ago
    brianm, I implemented this. Thanks! :-) I've just changed "if F == None" to "if f is None".

  • 0
    brianm 15 years ago
    This is a great addition, thank you! I did run into a problem using it in conjunction with IS_NULL_OR(IS_IN_DB(...)) because OPTIONS_WITH_ADD_LINK couldn't figure out field_name. After some experimenting, if came up with the following work around. 1) I added fourth parameter F which can either be None or the name of the field to use 2) Modified widgetAddLink.py as follows: # Get the parameters request = self.parameters["r"] a = request.application c = self.parameters["c"] T = self.parameters["T"] F = self.parameters["F"] #new paremeter either None or the name of the field to use requires = select.attributes["requires"] # If is not the "IS_IN_DB" validator then can be that the line below fails # because the requires can't have "ks" object try: # Get the field name from the foreign table from validator IS_IN_DB if F == None: field_name = requires.ks[0] or None #original module behavior else: field_name = F #use the one we specified (because there was no "ks" object) except AttributeError: return select

  • 0
    brianm 15 years ago
    Doh, apparently the comments don't preserve line breaks! Hopefully people can figure it out and, if appropriate, the slice code updated.

  • 0
    mrfreeze 15 years ago
    They do now :) You can also use html.

  • 0
    iacastillop 15 years ago
    for someone who has sophie's problems. The option exec('import applications.%s.modules.widgetAddLink as popup' % request.application) should be after the imports and the database creation.

  • 0
    sophie 15 years ago
    Hi i tried to put this in my program. But its not recognizing OPTION_WITH_ADD_LINK it appear this message "NameError: name 'OPTIONS_WITH_ADD_LINK' is not defined". The other problem i have in one of my tables i have person who has occupation, organization, specialty these are IS_IN_DB i have to put a create and validate one function for each tables? The last question is this support a pop up inside other popup, like categoryType -> category -> product. So in product i add my widget and also in categoryType. so when i click the link it should appear a popup and inside this another so i can insert the a new category and/or a new categoryType? I hope you can help me with this. And if you have a little example how to do this could you give it to me, i wold appreciate thsi a lot. Well thanks a lot. Bye Take care.

  • 0
    renatocaliari 15 years ago
    Sorry. I found some bugs and fix them. Changes: - The new step 2 was included. - The step 5 (now 6) was fixed.

  • 0
    dbb 15 years ago
    This is an excellent work!!!!so far no luck to run it, I have a default controller and many tables using IS_IN_DB, do I have to list all of them in validate_popup, and create_popup functions ( all tables referencing different tables); OPTION_WTH_ADD_LINK is unrecognized. In your example product is used as a table name and as a controller, please clarify. I have c= default, table name = x, a field in x is y, and y is referencing table name k and field name m in k, please can you walk me through this.

  • 0
    renatocaliari 15 years ago
    Make sure that the model and controllers have imported properly the widgetAddLink module (steps 5 and 7). Is there a file with the name "widgetAddLink.py" in your folder "modules"? Can you post a piece of the code of the model, including the lines that you import the module and the lines that calling the validator IS_IN_DB and the widget OPTIONS_WITH_ADD_LINK?

Hosting graciously provided by:
Python Anywhere