3

Please read below "Update: 2017-Aug-23 (20Hs)", I discovered this effect experimenting with Flask but it seems to be related only between DataTables and Bootstrap.

Implementing a Flask application I have rendered a table reading data by means of Pandas directly from a CSV file, that was no problem.

Then I decided to use DataTables in order to make of some features like scroll-bar/search/ordering first and later other more advanced features when implementing a database.

# file structure
#
# /testapp
#   +--- /app
#   |     +------ /templates
#   |     |           +------ events.html
#   |     +------ __init__.py
#   |     |
#   |     +------ events.csv
#   |     
#   +---- run.py
#

My __ init __ .py (where I render my events table) looks like:

# file: __init__.py 
import pandas as pd

from flask import Flask, render_template
from flask_bootstrap import Bootstrap

app = Flask(__name__, static_path = '/static', static_url_path = '/static')

bootstrap = Bootstrap(app)

@app.route('/')
@app.route('/events')
def events():
    return render_template('events.html', page='events')

and my events.html template looks like:

{% extends "bootstrap/base.html" %}
{% block content %}

{% block scripts %}
    {{ super() }}
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs/dt-1.10.15/datatables.min.css"/>
    <script type="text/javascript" src="https://cdn.datatables.net/v/bs/dt-1.10.15/datatables.min.js"></script>

    <script>
        $(document).ready(function(){
            if ( !$.fn.dataTable.isDataTable( '#myTable' ) ) {
                $('#myTable').DataTable( {
                    scrollY: 270,
                    paging: false
                } );
            }
        });
    </script>
{% endblock scripts %}

<div class="bootstrap-iso">
    <div class="container-fluid">      
      <table border="1" class="dataframe " id="myTable">
      <thead>
        <tr style="text-align: right;">
          <th></th>
          <th>Event</th>
          <th>Next Shutdown</th>
          <th>Next Startup</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>2017-08-20 15:06:18</td>
          <td>2017-08-20 16:06:00</td>
          <td>2017-08-21 07:30:00</td>
        </tr>
        <tr>
          <th>2</th>
          <td>2017-08-20 12:26:26</td>
          <td>2017-08-20 13:26:00</td>
          <td>2017-08-21 07:30:00</td>
        </tr>
      </tbody>
    </table>
    </div>
</div>

{% endblock %}

run.py file looks like:

from app import app
app.run(host='0.0.0.0', debug=False)

Now when rendering the events page I see shortly the original table (without DataTable) and one second later I see the table rendered again but in DataTable format.

Could anyone explain me what I am doing wrong here?

Should I use JavaScript sourced data like proposed here by DataTable?

I am using Flask and Bootstrap from Flask which uses jQuery version v1.12.4.

Thank you very much in advance for helping!

==============================

Update: 2017-Aug-22

This effect occurs when using Bootstrap. When no Bootstrap is used (means: no "extends "bootstrap/base.html"" in events.html and set the corresponding Datatables with no bootstrap) then the page is updated only once and Datatables is rendered correctly.

I saw other link like this (Bootstrap Issue) where a JS popover's function is called twice and I'm questioning if this is a similar problem...

I have also updated the files (see above init.py and events.html) with a minimum of code which reproduces the effect.

I have posted a question in DataTables discussion forum too (Link)

==============================

Update: 2017-Aug-23 (20Hs)

Thanks to people in DataTables forum the effect can be reproduced without any flask or python files by means of live datatables (link) !

Go to this link and add following line (from Bootstrap CDN)

into the HTML head:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

Now when you run the example by clicking on "Run with JS" button you will see first the HTML table and then the DataTable,

Im using DataTable 1.10.15, Bootstrap 3.3.7 and JQuery 1.12.4

This effect does not happens if the Bootstrap is not used.

==============================

Update: 2017-Sep-10

For me is the issued closed by using a new approach. Read my post at 2017-Sep-10 below.

2
  • In your position, I'd run the first three lines of events() at the Python REPL (after imports, of course) to verify that html_table is what you expect. Commented Aug 20, 2017 at 19:22
  • Thank you Dave, but three lines of events() seem to be working ok, in fact html_table is being rendered correctly (one time) when I do not use DataTable script. Commented Aug 20, 2017 at 20:34

4 Answers 4

2

Now when rendering the events page I see shortly the original table (without use of DataTable script) and then the DataTable is correctly rendered.

I misread that when I commented above. This doesn't appear to be either a pandas of Flask issue.

I threw together a test case to poke at a theory that something was stalling jQuery from thinking the page was ready, thus delaying the invocation of .DataFrame() until after the page had rendered. That would case the effect you're seeing. (I assume you're pulling in jQuery from the page you're overriding.)

You don't show the fragement that pulls in jQuery, and it looks like you're using Bootstrap. Are you pulling in other JS? Can you post that bit of code?

Looking at the DataTable docs, the only thing that jumped out is that the paths they recommend are different from the ones you're using (the doc I'm looking at doesn't have the v/bs/dt- part). I get a slightly different result switching between the two.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the advice I am pulling other things but seems not to be the problem. I have updated the description above with the whole files which reproduce the effect. With these files I am pulling only htm_table which is used by DataTable. Yes I am using Bootstrap. I hope you can reproduce the effect now.
Without having all of your source (and more time, which I don't have at the moment), the best I can offer now is a debugging strategy. The two ways I approach a problem like this are either to start small, building up just enough HTML, stepwise, until I can demonstrate the problem. Then, more than likely, it relates the the last thing I did.
Or, start big and subtract. Pull up the page in a browser, save it as a local file, and load that. Then remove things, step by step, until the problem goes away. I'd start by taking out Bootstrap. Good luck, and please report back with whatever you find.
I will keep trying and for sure will report the case here again. Thanks Dave!
0

I am using now another approach. I pass the table as sourced data (array) into DataTables and the HTML table is correctly rendered only once.

    @app.route('/')
    @app.route('/events')
    def events():
        with open("event.csv",'r') as dest_f:
            data_iter = csv.reader(dest_f, delimiter = ',')
            data = [data for data in data_iter]
        return render_template('events.html', page='events', html_table=data)

I do not know why the other way is rendered two times but with this new approach I get what I wanted !

    <script>

        var dataSet = {{ html_table | safe }}

        $(document).ready(function(){
            if ( !$.fn.dataTable.isDataTable( '#myTable' ) ) {
                var table = $('#myTable').DataTable( {
                    "data" : dataSet,
                });
            }

        });

    </script>


...

    <table id="myTable" class="display nowrap dataframe" width="100%">
    </table>

Comments

0

It doesn't work for me. I delete all elements and re-create.

  $('.table-responsive').html('<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0"></table>')
  $(document).ready(function() {  
    $('#dataTable').DataTable( {
        ajax: '/admin/users',
        columns: <%= raw @users_attrs.to_json %>
      });
  });

Comments

0

I had the same issue. I could not find any proper solution. So I fixed this with DOM manipulation as a hack.

Following is my table:

<div id = "client-table" class="card">
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger">
</div>

  1. Hide the table from view by DOM manipulation at the beginning:
document.getElementById('inner-table').style.display = 'block';
  1. Then, when the table is rendered, show the table:
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
          document.getElementById('client-table').style.display = 'block';
        });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.