1

I am still in the process of learning how everything works, but I am trying to put together a project that has a table that needs to be sorted. I am using flask to generate the pages, and plan to keep the information for the table stored in sql. For the time being, I am using a hard-coded table of dictionaries that will eventually be converted from this sql database. I have successfully gotten my html page to load the flask table element into a table on the webpage. However, I would like to allow users to be able to sort through this table, and I believe using Javascript would be the best way to do this.

However, before I begin to write the sorting function, the problem I am having is somehow passing the table of dictionaries that is rendered in Flask into my Javascript file. I believe it would be best to have the html render the table from Flask first, and then have Javascript retrieve the table information straight from the html page.

To be clear, the format of the table in Flask is like this:

items = [{'item 1': "Name", 'item 2': "Name"}, {'item 1': "Name2", 'item 2': "Name2"}]

and is rendered in the html page like this:

            {% for row in items %}
            <tr>
                <td class="item1">{{ row.item1 }}</td>
                <td class="item2">{{ row.item2 }}</td>
            </tr>
            {% endfor %}

And somehow, I would like to render the same "items" variable in Javascript using the html page as its source. I have been able to find tutorials explaining a sorting function in Javascript however, these tutorials assume that the table already exists in JS, and I am unsure how to render it dynamically like this. Does anyone know how I would go about doing this? Thanks.

Zernst
  • 315
  • 4
  • 17
  • Sorting DOM elements is not the preferred method. Better to sort the `items` array, then replace the existing table elements with the sorted data (assuming you have access to the `items` array). – terrymorse May 06 '20 at 17:10
  • That is interesting. I guess I should clarify, I want the html table sorted dynamically, depending on which header is clicked. My research suggested this was possible using Javascript and that is why I wanted to use the DOM. I know I could have each table header process a separate function in flask in which case the sql code is sorted before it is input into the render template, but wouldn't that make the website reload every time the table is sorted? That is the thing I am trying to avoid. Thanks. – Zernst May 06 '20 at 19:13
  • @Zernst Have a look at the [datatables.js library](https://datatables.net/). This lets you make any HTML table into an interactive one with things like search and pagination. If this is what you're after let me know and I can add an answer that is relevant to the code in your question. – v25 May 06 '20 at 19:53
  • Yes, that is the answer to what I was looking for! I actually just stumbled upon it as well, I can't believe I couldn't find that before. Thank you so much for your help! – Zernst May 06 '20 at 19:58
  • @Zernst Cool, I've added an answer, hopefully this helps. It uses list comprehension which may be confusing at first so please let me know if you wish me to expand on what's happening there. – v25 May 06 '20 at 22:04
  • @v25 I think I have been able to figure out its basic functionality. Thank you again! – Zernst May 07 '20 at 18:30

1 Answers1

0

As mentioned, datatables would be a good fit for your frontend, as it handles all the pagination, sort and search functionality automatically.

You may wish to have a look at the repo search-generic-tables. This is my implementation that uses an SQLite database, but most of what you're probably looking for is there.

The templates are built in such a way that data isn't hard coded into them. Many Flask tutorials involve hard-coding headers into the template <td>Header Name</td> which stops the templates from being generic.

If you don't want to clone the whole repo, you could probably just copy both templates from the templates folder, which include the required CDN links to make datatables work.

To make this work with your code, (note the following assumes every dictionary in your list has the same keys!) you could do the following. Let's call your list of dictionaries original_items and make the values unique for clarity:

original_items = [{'item 1': "Banana", 'item 2': "Car"}, {'item 1': "Apple", 'item 2': "Bike"}]

Define a function which makes this into a list of OrderedDicts. This will keep the column order predictable in the table:

import collections
def sort_dict(d):    
    return collections.OrderedDict(sorted(d.items()))

ods = [sort_dict(d) for d in original_items]

Now make these into a list of lists:

table_items = [ list(v for _,v in od.items()) for od in ods]

table_items is now a list of lists, which looks like:

[['Banana', 'Car'], ['Apple', 'Bike']]

Then get the headers from the first dictionary in the ods list:

headers = [k for k,_ in ods[0].items()]

headers now looks like:

['item 1', 'item 2']

So passing these through to the template becomes as simple as a view function which looks like:

@app.route('/all')
def all():
    return render_template('index.html', headers=headers, objects=table_items)

This renders nicely in the browser:

rendered table

If you want to change the left-right ordering of the columns, datatables provides a convenient way to do this natively without the need to change your Python code.

v25
  • 7,096
  • 2
  • 20
  • 36
  • Thank you so much, you have given me way more help than I expected. I will check out everything you wrote here, as it is very useful information for me formatting my tables with headers. Thank you again! – Zernst May 07 '20 at 18:31
  • I do have one more thing I would like to try, and instead of a new thread, maybe you know the resources I need to get it done. As it is now, this works, and the structure was that I returned the table data in my flask app file, and then populated the html from that ``` return render_template("/items.html", items=items) ``` – Zernst May 07 '20 at 19:07
  • Hey, I apologize, I answered my own question, and though I deleted my comment, so nevermind. Thank you for all of your help! – Zernst May 08 '20 at 01:41