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

 

***  VVMSelectWidget - OPTIONS chain widget for web2py  ***
*** Created by Vadim V. Mostovoy, vadim *at* routix.net ***

    
INSTALLATION:
        - just place file "vvm_select_widget.py" into "models" folder;
          now you can create widget instances in your controllers!
    
DESCRIPTION:
        - creates dependent OPTIONS chain (cascade);
        - integrated "select-or-add-new" functionality (ajax + jQuery-ui dialog);
        - can be used as "select-or-add-new" for a single not cascaded dropdown list;
        - works in both cases, record creation and record updating;
        - adjustable or default fields representation (formats);
        - adjustable or default placeholders;
        - it is up to you, near which dropdown to show "Add..." links;
        - uses default validators, css, etc.;
        - self-sufficient, no additional views, controllers, models needed;
        - multiple widgets per page allowed;
        - you can provide you own javascript dropdown-change event handler
          to react on select/deselect event;
        - secure (there is no way to create fake request with substituted tables/fields
            to attack your application; only specified tables can be changed);
          
    NOTES:
        - uses jQuery and jQuery-ui javascript libraries;
          default "layout.html" imports those libraries into your aplication by default;
          if you use customized views which do not import jQuery libraries, you must 
          load those libraries explicitly into your view before using this widget;
 
 
EXAMPLE MODELS:
 
        db.define_table('Kind',
            Field('Name', length=50, unique=True, required=True, notnull=True, label="Product kind"),
            format='%(Name)s')

        db.define_table('Category',
            Field('Kind_id', db.Kind, required=True, notnull=True, label="Kind"),
            Field('Name', length=50, required=True, notnull=True, label="Category name"),
            format='%(Name)s')

        db.define_table('Subcategory',
            Field('Category_id', db.Category, required=True, notnull=True, label="Category"),
            Field('Name', length=50, required=True, notnull=True, label="Subcategory name"),
            format='%(Name)s')
            
        db.define_table('Product',
            Field('Subcategory_id', db.Subcategory, required=True, notnull=True, label="Product group"),
            Field('Name', length=100, required=True, notnull=True),
            format='%(Name)s')

   

EXAMPLES:

1. Simple way

        # define tables hierarchy
        sel_widget = VVMSelectWidget(db.Kind, db.Category, db.Subcategory)

        # set widget, note: you must set widget to field with "set_widget_to()" method!
        sel_widget.set_widget_to(db.Product.Subcategory_id)

        return dict(crud=crud.create(db.Product))
        # or:
        #return dict(crud=crud.update(db.Product, 13))

2. More configurable way

        # fields formats/representations; if all or some omited - default formats
        # will be used; Formats can be either strings or functions
        formats = dict(Kind="%(Name)s", Category="%(Name)s", Subcategory=lambda row: "%(Name)s (%(id)s)" % row)

        # placeholder used when selected nothing; if omited - default will be used
        # can be either string or function
        placeholder = lambda table: "Select %s..." % str(table).lower()

        # define fields for which we will show "Add..." links
        # Note: db.Kind is omited; This means that user cannot add new records to db.Kind
        add_links_to = [db.Category, db.Subcategory]

        # width for dialog; if omited - sizes will be ajusted automatically
         dialog_width=500
         dialog_height=300

        # create widget instance
        sel_widget = VVMSelectWidget(db.Kind, db.Category, db.Subcategory, 
                     placeholder=placeholder, 
                     formats=formats,
                     dialog_width=dialog_width,
                     dialog_height=dialog_height,
                     add_links_to=add_links_to)

        sel_widget.set_widget_to(db.Product.Subcategory_id)

        return dict(crud=crud.create(db.Product))

3. If you need just "Add..." link next to your single dropdown, but not cascading your dropdowns - just omit tables hierarchy list in the constructor!

        # create class without tables hierarchy
        # in this case widget will add link for
        # a new record creation and nothing more
        sel_widget = VVMSelectWidget()

        sel_widget.set_widget_to(db.Product.Subcategory_id)

        return dict(crud=crud.create(db.Product))

4. Sometimes you need to show/hide other page elements as a result of dropdown select/deselect event; in this case you can supply your own event handler to widget; here is an example of dropdown color changing; color value depends on dropdown value; NOTE: be careful, poorly written javascript event handler can halt execution of other javascript code on your page! use exception catching in your event handler; in any case your javascript code must not raise any exceptions and must have correct javascript syntax

        # define javascript event handler
        change_handler_js = """

            function(dropdown) {
                if ($(dropdown).val() > 0)
                    $(dropdown).css('background-color', '#EBF5CC');
                else
                    $(dropdown).css('background-color', '#FFE6E6');
            }

        """

        # define tables hierarchy and set your js event handler
        sel_widget = VVMSelectWidget(db.Kind, db.Category, db.Subcategory,
            change_handler_js=change_handler_js)

        # set widget
        sel_widget.set_widget_to(db.Product.Subcategory_id)

        return dict(crud=crud.create(db.Product))

 

Related slices

Comments (6)

  • Login to post



  • 0
    gustavo-jung-11515 9 years ago

    How do I change the name of the table that appears on the dropdown arrow?


  • 0
    fernando-vieira-10469 10 years ago

    the widget no work, i get the following error:

     

     

    <type 'exceptions.NameError'> global name 'VVMSelectWidget' is not defined

     

    i copy vvm_select_widget .py for models folder and create function in controller with  1. Simple way


  • 0
    craxsnet 11 years ago

    Hello,

    with the new version of web2py 2.2.1,  the widget no work, i get the following error:

     
    var dropdownChangeHandler_VVM_Options_widget_notas_subcategoria_id = null;

     

    replies (4)
    • craxsnet 11 years ago

      Yes......Thank you very much

    • segmentation-fault 11 years ago

      FIXED.

    • craxsnet 11 years ago

      I tried to send you an email with the HTML code, because did not work what you have wrote, but the server returned the mail.

    • segmentation-fault 11 years ago

      Hi, I think there is an error in code: try to find and replace "Content-type" with "Content-Type" in widget code. Let me know if it helped. Send me also full HTML page output to vadim -a-t- routix.net if you can.


  • 0
    hervé-mayou-10727 11 years ago

    Hello,

    Are there options to take care of a case like this one, where child_atom would change according to parent_atom?

     

     

    db.define_table('atom',
        Field('value', 'string', unique=True, required=True),
        Field('description', 'text'),
        auth.signature,
        format='%(value)s'
    )
    db.define_table('user_atom',
        Field('user', db.auth_user, required=True),
        Field('top_atom', db.atom, default=1, required=True),
        Field('parent_atom', db.atom, required=True),
        Field('child_atom', db.atom, required=True),
        auth.signature
    )
    

    If not, I can (eventually) provide help to (eventually) add them...

     
    Thanks
    replies (1)
    • segmentation-fault 11 years ago

      Hey! It was designed with multiple tables in mind. Sorry, but for your case this widget will be overkill.


  • 0
    craxsnet 11 years ago

    ERROR

    
        sel = SELECT(*opts, _parent_id=parent_id, **attr)
                                     ^
    SyntaxError: invalid syntax
    replies (4)
    • craxsnet 11 years ago

      its works, thank you

    • craxsnet 11 years ago

      ok , i try it and give you my feedbak, thanks.

    • segmentation-fault 11 years ago

      Hi, can't reproduce this error. To be honest I can't see what is wrong with syntax here? Someone has the same error? Try to replace this line with following two: attr["_parent_id"] = parent_id sel = SELECT(*opts, **attr) Please give me feedback if it helped or not. Thanks.

    • craxsnet 11 years ago

      in line 295

show more comments

Hosting graciously provided by:
Python Anywhere