KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

Progress Bar Async Loader Help #2500

Closed cfsinc opened this topic on on Dec 16, 2021 - 8 comments

cfsinc commented on Dec 16, 2021

Koolreport Support Staff,

I have a report that takes about 10 to 12 seconds or longer to load

During that time I need a progress circle to show until the report has fully loaded. I have tried numerous things but I have been unsuccessful to get the progress circle to load before the page has finished loading. It will load slightly before the page is rendered but not until 8 to 10 seconds after page is selected or run to refresh data on page is selected. I will make a donation as always if you can please help me with this. Im not using the dashboard. This is single run and render reports and I have tried a sub report but still cant get it to work right?

I have tried the following

https://www.koolreport.com/forum/topics/1118

https://www.koolreport.com/forum/topics/2004

https://www.koolreport.com/forum/topics/185

This is what my latest version of my code looks like but its still not right. The progress circle wont load until the page has finished processing and I need it to show from when the page is selected until the page is finished rendering. my code is a mess right now because im trying everything to get the circle to show during load and commented code is things I have tried. I have tried the subreport and doing this as a regular report and have tried all I can find in the Forum.

Even if you can just give me examples of clean code for index.html and run.report.php

Below is my latest unsuccessful code trying to do a subreport to try and make it work.

index.php

run.report.php

promiseReport.php

promiseReport.view.php

CSS for the loader

index.php

<?php
//global $mod;
//if (!isset($mod)) { echo 'Can\'t access this page directly.'; exit;}
//include "run.report.php";
?>
<!DOCTYPE html>
<html lang="en">

<script type="text/javascript" src="modules/reports2/assets/theme/js3/jquery.min.js"></script>

<head>
<!--    <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>-->

    <script>
        function updateDashboard(){
            subReport.update("showTime");
        }

        $(document).ready(function(){
            setInterval(updateDashboard, 1000);
        });
    </script>
    <script>
        var myVar;

        function myFunction() {
            myVar = setTimeout(showPage, 10);
        }
        function showPage() {
            document.getElementById("loader").style.display = "none";
        }
    </script>
</head>
<body onload="myFunction()" style="margin:0;">
<div id="loader" class="loader"></div>
<?php
ob_start();
flush();
//include "dashboard.php";
include "run.report.php";
//exit;
?>
</body>
</html>
<?php
    ob_end_flush();
exit;
?>

run.report.php

<?php
global $mod;
global $app;
if (!isset($mod)) { echo 'Can\'t access this page directly.'; exit;}
require_once "promiseReport.php";
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="description" content=" Promise Report">
    <meta name="author" content="">
    <meta name="keywords" content="Reports, Promise Report">

    <title><?php //echo $example["title"] ?>Promise Report <?php echo date("m-d-y H:i:s")." Emp ".$app->user_id ?></title>

    <link href="modules/reports2/assets/fontawesome/font-awesome.min.css" rel="stylesheet">
    <link href="modules/reports2/assets/simpleline/simple-line-icons.min.css" rel="stylesheet">

    <link href="modules/reports2/assets/bs5/css/bootstrap.min.css" rel="stylesheet">
    <link href="vendor/koolreport/datagrid/DataTables/datatables.min.css" rel="stylesheet">
    <link href="modules/reports2/assets/css/global_custom.css" rel="stylesheet">
    <link href="modules/reports2/promisereport/css/promisereport_custom.css" rel="stylesheet">

    <script type="text/javascript" src="modules/reports2/assets/theme/js/jquery.min.js"></script>
    <script type="text/javascript" src="modules/reports2/assets/theme/js/bootstrap.bundle.min.js"></script>

</head>
<!--<body onload="myFunction()" style="margin:0;">-->
<body style="margin:0;">
<!--<div id="loader" class="loader"></div>-->
<!--<div style="display:none;" id="myDiv" class="animate-bottom">-->
    <main role="main" class="container">
        <?php

            $report = new promiseReport();
            $report->run()->render();
        ?>
        <script>
            // var myVar;
            // function myFunction() {
            //     myVar = setTimeout(showPage, 3000);
            // }
            // function showPage() {
            //     document.getElementById("loader").style.display = "none";
            //     document.getElementById("myDiv").style.display = "block";
            // }
        </script>
    </main>
</body>
</html>
<?php
//    ob_end_flush();
    exit;
?>

My CSS for the loader

/* following is the page loader class animation progress circle will change to progress bar later*/
#loader {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 1;
    width: 150px;
    height: 150px;
    margin: -75px 0 0 -75px;
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid #3498db;
    -webkit-animation: spin 2s linear infinite;
    animation: spin 2s linear infinite;
}
@-webkit-keyframes spin {
    0% { -webkit-transform: rotate(0deg); }
    100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
/* Add animation to "page content" */
.animate-bottom {
    position: relative;
    -webkit-animation-name: animatebottom;
    -webkit-animation-duration: 1s;
    animation-name: animatebottom;
    animation-duration: 1s
}
@-webkit-keyframes animatebottom {
    from { bottom:-100px; opacity:0 }
    to { bottom:0; opacity:1 }
}
@keyframes animatebottom {
    from{ bottom:-100px; opacity:0 }
    to{ bottom:0; opacity:1 }
}
#myDiv {
    display: none;
    text-align: center;
}


Sebastian Morales commented on Dec 17, 2021

Hi, this is a perfect case for using subreport. You would have to create 2 reports: Main/loader report which contains the other report which is your data subreport, e.g promiseReport:

class LoaderReport extends \koolreport\KoolReport
{
    use \koolreport\core\SubReport;

    function settings()
    {
        return array(
            "subReports"=>array(
                "promiseReport"=>promiseReport::class,
            )
        );
    }
} 

In your data subreport by default don't load any data so that initial page load is very fast:


class promiseReport extends \koolreport\KoolReport
{
    ...
    function setup()
    {
        if(isset($this->params["loadData"])) // only load and process data when there is loadData parameter
        {
            $this->src("..")
            ->query("...")
            ...
        }
    }
}
//promiseReport.view.php: similary only show view content if (isset($this->params["loadData"])) 

Then once the main/loader report is rendered you could setTimeout to call for data subreport to load data:

//LoaderReport.view.php
<?php $this->subReport("promiseReport"); ?>
<!--
    show your CSS loader icon here
-->
<script>
        setTimeout(showPage, 10);
        function showPage() {
            subReport.update("promiseReport",{
                "loadData":1, 
            }); // load promiseReport with parameter loadData = 1
        }
</script>

And remember to hide the CSS loader icon once your promiseReport view is shown:

//promiseReport.view.php
<?php
if (isset($this->params["loadData"])) 
{
?>
<!-- show your promiseReport content here -->
<script>
    // hide CSS loader icon here
</script>
<?php
} 
?>

Let us know if you have any question with this approach. Tks,

cfsinc commented on Dec 22, 2021

Thank you so much for your help. I was. traveling so I have not had much time to work on this until now. I have progressed but still not working correctly.

Here are my files

index


<?php
include "dashboard.php";
//include "run.report.php";
exit;
?>

Then to dashboard.php and dashboard.view.php

//dashboard.php
<?php
require_once "vendor/koolreport/core/autoload.php";

//include "showTime.php";
include "promiseReport.php";

class dashboard extends \koolreport\KoolReport
{
    use \koolreport\core\SubReport;

    public function settings()
    {
        return array(
            "subReports"=>array(
                //"showTime"=>showTime::class
                "promiseReport"=>promiseReport::class
            )
        );
    }

    public function setup()
    {
    }
}

$d1 = new dashboard;
$d1->run()->render();
?>

//dashboard.view.php
<?php
use koolreport\widgets\koolphp\Card;
//$this->subReport("showTime");
$this->subReport("promiseReport");
?>
<div id="loader" class="loader" onload="loadFunction()"></div>

<script>
    var myVar;
    function loadFunction() {
       myVar = setTimeout(showPage, 10);
       //myVar = showPage
    }
    function showPage() {
        document.getElementById("loader").style.display = "none";
    }
</script>
<!--<script>-->
<!--    setTimeout(showPage, 10);-->
<!--    function showPage() {-->
<!--        subReport.update("promiseReport",{-->
<!--            "loadData":1,-->
<!--        }); // load promiseReport with parameter loadData = 1-->
<!--    }-->
<!--</script>-->

my promise report page loads without processing data like you suggested. That is great. I am having trouble with how to stop the loader and how to call the loadData 1 to process the report clicking the run button. I do want the report layout to show so I just stopped the processing on report load only.

I do have the following in my promiseReport.php to stop the processing until the loadData is set `

    if(isset($this->params["loadData"])) // only load and process data when there is loadData parameter
    {
I need my runreport button to set the loadData to 1 and process the report I also had to keep the options and date still processing so it can be secected. Here is all the code. Im sure im just missing something dumb on my part.



//in promiseReport.view.php I need the button to set the loadData to 1

</div>

                    <div class="row">
                        <div class="form-group">
                            <button class="dt-button buttons-html5" id="submitForm1" name="submitForm1" >Run Report</button>
                        </div>
                    </div>
I also am having trouble calling the progress right to stop? Here is the code at the end of the promise Report



<?php if (isset($this->params["loadData"])) { ?> <!-- show your promiseReport content here --> <script>

document.getElementById("loader").style.display = "none";

</script> <?php } ?>

<script>
    //document.getElementById("loader").style.display = "none";
</script>

</div>

</main> </body> </html> `

cfsinc commented on Dec 22, 2021

It almost works, just cant get the spinning progress bar to stop right and cant get the data to process after the run button is pressed.

Here is what the report looks like when its loaded without data and ready to press run button. When I click run and I have tried a few things to get the run button to allow the report to process this is as close as I have gotten.

cfsinc commented on Dec 22, 2021

I apologize for having to go this far for help but I just cant get it working in a timely manner.

Sebastian Morales commented on Dec 22, 2021

Pls put a hidden input with name="loadData" and value="1" inside your form so that when you click submit there's an input value named "loadData":

    <form>
        <input type="hidden" name="loadData" value="1" /> <!-- type="hidden" because it's used for our data processing purpose, not for users to input -->
                        <div class="form-group">
                            <button class="dt-button buttons-html5" id="submitForm1" name="submitForm1" >Run Report</button>
                       </div>
    </form> 
cfsinc commented on Dec 22, 2021

Ok I tried what you suggested and it does not work

The addition of the following in promiseReport.view.php is not working. It is not passing the param back to my promiseReport.php and allowing the if isset to run. No matter where I place the input type hidden in the form it does not pass that param back to allow if isset code to run.

if(isset($this->params["loadData"]))

<input type="hidden" name="loadData" value="1" />

cfsinc commented on Dec 22, 2021

I forgot to add loadData to bindParamsToInputs() so once that was done what you told me to do with input hidden does work

KoolReport commented on Dec 23, 2021

That's great to hear that it works and thank you very much for your generous tip! Really appreciated.

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
help needed
solved

None