Datatable not initialising. Vue.js and Gridstack (Laravel)

Datatable not initialising. Vue.js and Gridstack (Laravel)

MickBMickB Posts: 103Questions: 25Answers: 2

Hello,

I'm really struggling to get my Datatable to initialise when my page loads.

This is a bit of a work in progress, so apologies if it is a bit of a mess.

If I do this in the console after the page load, the Datatable loads correctly.

$('#content-id-2').DataTable();

It looks like a timing problem but I'm not certain.

http://debug.datatables.net/exijuw

Here is the HTML template:

@extends('layouts.app')

@section('head')

    <style>
        .chart-sized {
            height: 200px;
            width: 50%;
            background-color: powderblue;
        }
    </style>

    <script src="{{ elixir('js/all.js') }}"></script>





@endsection


@section('content')

    <div id="page-wrapper">

        <div class="row">
            <div class="col-lg-12">
                <h1>Dashboard</h1>
                <div class="alert alert-dismissable alert-warning">
                    <button data-dismiss="alert" class="close" type="button">&times;</button>

                    This is a message

                </div>
            </div>
        </div>


        <div class="row">
        </div>
    </div>

    <h1>Gridstack.js and Vue.js</h1>

    {{--https://troolee.github.io/gridstack.js/--}}
    <div id="app">

    <div class="grid-stack">


        <chart-widget v-for="widget in chartsList" v-bind:widget="widget"></chart-widget>

        <table-widget v-for="widget in tablesList" v-bind:widget="widget"></table-widget>

        <gauge-widget v-for="widget in gaugesList" v-bind:widget="widget"></gauge-widget>

    </div>

    <br>
        <button class="btn btn-default" id="save-grid" v-on:click="savePositions">Save Grid</button>
    </div> {{--app--}}

    <script src="/js/dashboard.js"></script>

@endsection


@section('js')

    <script>




        </script>

@endsection



and the JS.




//register a global component for gauges Vue.component('gauge-widget', { props: ['widget'], template: '<div class="grid-stack-item":data-gs-x="widget.x" :data-gs-y="widget.y" :data-gs-width="widget.width" :data-gs-height="widget.height" :id-for-save="widget.id">'+ '<div class="grid-stack-item-content" :id="widget.contentId"></div>'+ '</div>' }); //register a global component for charts Vue.component('chart-widget', { props: ['widget'], template: '<div class="grid-stack-item":data-gs-x="widget.x" :data-gs-y="widget.y" :data-gs-width="widget.width" :data-gs-height="widget.height" :id-for-save="widget.id">'+ '<div class="grid-stack-item-content" :id="widget.contentId"></div>'+ '</div>' }); //register a global component for tables Vue.component('table-widget', { props: ['widget'], template: '<div class="grid-stack-item" :data-gs-width="widget.width" :data-gs-height="widget.height" :id-for-save="widget.id" :data-gs-x="widget.x" :data-gs-y="widget.y">'+ '<div class="panel panel-primary grid-stack-item-content " >' + '<div class="panel-heading">' + '<h3 class="panel-title"><i class="fa fa-bar-chart-o"></i>{{ widget.title }}</h3>' + '</div>' + '<div class="panel-body" >' + '<table :id="widget.contentId" class="display" cellspacing="0" width="100%">'+ '<thead>'+ '<tr>'+ /* http://www.ctlevi.com/software/2015/02/26/vuejs-simple-paginated-table-with-search.html*/ '<th v-for="header in widget.headers">'+ '{{header}}'+ '</th>'+ '</tr>'+ '</thead>'+ '<tbody>'+ '<tr v-for="row in widget.data">' + '<td v-for="column in row">'+ ' {{ column }}'+ '</td>'+ '</tr>' + '</tbody>'+ '</table>'+ '</div>' + '</div>' + '</div>' }); window.onload = function () { vm = new Vue({ el: '#app', data: function () { return { chartsList: [], gaugesList: [], tablesList: [] }; }, mounted: function () { axios.get('/dashboardWidgets?dashboard=1') .then(function (response) { vm.chartsList = response.data.chartsList; vm.gaugesList = response.data.gaugesList; vm.tablesList = response.data.tablesList; initialiseWidgets(); }) .catch(function (error) { console.log(error); }); }, methods: { savePositions: function (event) { //This does not seem very Vue like //I really want to bind these somehow so I don't have to get them from the DOM var widgetPositions = _.map($('.grid-stack .grid-stack-item:visible'), function (el) { el = $(el); var node = el.data('_gridstack_node'); return { id: el.attr('id-for-save'), x: node.x, y: node.y, width: node.width, height: node.height }; }); axios.post('/savePositions', { params: { positions: widgetPositions } }) .then(function (response) { console.log(response); alert('Done'); }) .catch(function (error) { console.log(error); }); } } }); }//end of onload function initialiseWidgets() { console.log('loading charts') vm.chartsList.forEach(initialiseChart); console.log('loading gauges') vm.gaugesList.forEach(initialiseGauge); //now we have the widgets we can fire up Gridstack console.log('loading gridstack') /*Gridstack*/ $(function () { var options = { cellHeight: 100, verticalMargin: 10 /*disableResize: true*/ }; $('.grid-stack').gridstack(options); }); `` console.log('loading tables') vm.tablesList.forEach(initialiseTable); }//initialiseWidgets function initialiseGauge(item,index){ FusionCharts.ready(function () { var fusionGauge = new FusionCharts({ "type": item['type'], "renderAt": item['contentId'], "width": "100%", "height": "100%", "dataFormat": "json", "dataSource": { "chart": { "caption": "Customer Satisfaction Score", "subcaption": "Last week", "lowerLimit": "0", "upperLimit": "100", "theme": "fint" }, "colorRange": { "color": [ { "minValue": "0", "maxValue": "50", "code": "#e44a00" }, { "minValue": "50", "maxValue": "75", "code": "#f8bd19" }, { "minValue": "75", "maxValue": "100", "code": "#6baa01" } ] }, "dials": { "dial": [ { "value": "67" } ] } } }); fusionGauge.render(); }) } function initialiseTable(item,index){ test = $('#content-id-2').DataTable(); console.log(test); } function initialiseChart(item,index){ FusionCharts.ready(function () { var fusionChart = new FusionCharts({ "type": item['type'], "renderAt": item['contentId'], "width": "100%", "height": "100%", "dataFormat": "json", "dataSource": { "chart": { "caption": item['title'], "subCaption": item['description'], "xAxisName": "Month", "yAxisName": "Revenues (In USD)", "theme": "fint" }, "data": item['data'] } }); fusionChart.render(); }); }//initialiseChart $("#menu-toggle").click(function(e) { e.preventDefault(); $("#wrapper").toggleClass("toggled"); });

Replies

  • MickBMickB Posts: 103Questions: 25Answers: 2

    Just hacked this in:

     setTimeout(function(){
    
       test = $('#content-id-2').DataTable();
    
          alert (test);
       
       },5000);
    
    

    and the Datatable now initialises correctly.

    This confirms it is a timing problem, just not sure how to handle it in a sensible way.

    Mick

  • allanallan Posts: 63,683Questions: 1Answers: 10,498 Site admin

    It does indeed sound a lot like a timing issue.

    I'm not familiar with Vue.js at all I'm afraid. Does it have a callback to say when the widget has been initialised? If so, that would be the time to initialise DataTables.

    Allan

  • MickBMickB Posts: 103Questions: 25Answers: 2

    Yes,

    mounted:

    https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

    This is a tricky one, there is a lot of stuff going on.

    In mounted, I call initialiseWidgets, which calls vm.tablesList.forEach(initialiseTable); which is where I want to fire up the Datatable (anywhere would be better than using the timer).

    I did have this working, when all the code was in the template, now I'm trying to refactor it all out.

    Mick.

  • allanallan Posts: 63,683Questions: 1Answers: 10,498 Site admin

    HI Mick,

    I hate to say it, but I think this might be one for the Vue.js folks. If the element isn't in the DOM when the mount happens, it sounds like there is something else going on.

    Allan

  • MickBMickB Posts: 103Questions: 25Answers: 2

    No worries. Allan.

    Thanks for looking. I will let you know how I get on.

    i still have some refactoring to do, so that might change the timings a bit.

    Mick

  • MickBMickB Posts: 103Questions: 25Answers: 2

    FYI I stuck this in:
    console.log($('#content-id-2'));

    and the table doesn't exist at this point, so no way to convert it into a DT.

  • MickBMickB Posts: 103Questions: 25Answers: 2

    There is also an updated callback. I have stuck the initialise in there and it's now working.

  • allanallan Posts: 63,683Questions: 1Answers: 10,498 Site admin

    Brilliant! Good to hear you'e got it working.

    Allan

This discussion has been closed.