If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!
Example Scenario:
 
Consider this model:
 
db.define_table('house',
    Field('location_type', requires=IS_IN_SET(['city', 'country', 'sea'])),
    Field('location_type_msg'),
    Field('capacity', requires=IS_IN_SET(['single', 'couple', 'small family', 'big family']),
    Field('capacity_msg'))
you can see the pattern I used in the field names, "fieldname" followed by "fieldname_msg".
 
Now, what I want to do is to generate a grid with only two columns "location_type" and "capacity" where "location_type_msg" and "capacity_msg" would be accessible once you mouse hover  through their respective fields.
 
Example:
 
id | location_type |     capacity
=======================================
1  |     city      |       single
2  |     sea       |     small family
 
now if i go over the word 'city' I would see something like "New York" or "London" and if I mouse hover "small family" i would see something like "90 square meters"
 
Answer:
 
on the db file, add the following:
def get_column_index(grid, colname):
    colname = colname.replace('.','-')
    for col in grid[2][0][0][0]:
        if col['_id'] == colname:
            return col['data']['column']-1
    return -1

def apply_title_to_column(grid, title_list, column_number):
    for cell,title in zip(grid[2][0][0][2], title_list):
        if title is not None and str(title) != "<td></td>" and str(title) != "<td>None</td>":
            cell[column_number]=TD(cell[column_number][0],_title=title)

def get_table_rows(grid):
    return grid[2][0][0][2]

def get_column(grid, column_number):
    return [row[column_number][0] for row in get_table_rows(grid)]

def remove_grid_column(grid, column_number):
    del grid[2][0][0][0][column_number]
    del grid[2][0][0][1][0][column_number]
    for row in get_table_rows(grid):
        del row[column_number]

def add_titles(grid):
    cols_to_delete=[]
    if grid.rows:
        for colname in grid.rows.colnames:
            if colname.endswith('_msg'):
                column_index = get_column_index(grid, colname)
                cols_to_delete.append(column_index)
                title_list = get_column(grid, column_index)
                apply_title_to_column(grid, title_list,  get_column_index(grid, colname[:-4]))
        for col_number in reversed(cols_to_delete):
            remove_grid_column(grid, col_number)
    return grid
view code:
{{=LOAD('default','housegrid.load', ajax=True)}}
 
Notes:
  • this code is outrageous, egregious, preposterous but it works and it's quite modular if you want to use it for other changes like this.
  • one nice detail about this is that you can still make all your queries, including within the fields that are now only being shown on mouse hovering 
  • an alternative approach would be to use jQuery manipulations in the DOM but this looks a lot more resilient and decoupled from the view side of things
  • obviously, this uses internals that can be modified at any time so backward compatibility can not be assured even though this should be very rare.
  • it would be nice to have an API for grids. I think there is this big "jump" from database records to generated HTML code ready to be rendered, not so much control over the Application logic on it.

 

Related slices

Comments (0)


Hosting graciously provided by:
Python Anywhere