KoolReport's Forum

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

Issue with Modal Popups when Report rendered in Page #2293

Closed Ron opened this topic on on Aug 22, 2021 - 46 comments

Ron commented on Aug 22, 2021

When I render a report inside a page I have an issues with bootstrap modal. it gives an error .modal in not a function. my report does not include any bootstrap extensions(not BostrapCss and not Amzing theme) but still it give the same error. when I put the same report in a modal and show it by click it works. only when I embed it in the page itself.

Ron commented on Aug 23, 2021

?

Sebastian Morales commented on Aug 24, 2021

Ron, pls post your report view code and screenshots of the error if possible. Tks,

Ron commented on Aug 24, 2021
<?php
require_once APPPATH."Libraries/koolreport/core/autoload.php";
use \koolreport\cube\processes\Cube;
use \koolreport\processes\Filter;

class Class_schedule extends \koolreport\KoolReport
{
    use \koolreport\export\Exportable;
    var $classList = null;

    function setup()
    {
       
        if ( $this->params['class_id'] != 0 ) {
            $this->classList[] = array('id'=>$this->params['class_id'], 'class_name'=>'');
        } else {
            $this->classList = is_array($this->params['class_list']) ? $this->params['class_list'] : [] ;
        }
        $this->src("db")
        //the last parameter 1 hides nn scedulabale professions 0 shows all.
        ->query('CALL getClassSchedule(:year, :class_id, 1)')
        ->params(array(
            ':year' => $this->params['year'],
            ':class_id' => $this->params['class_id']
        ))
        ->saveTo($node1);

        foreach ($this->classList as $class) {
            $node1->pipe( new Filter( array (
                //array("class_id", "=", $class['id'])
                array("class_id","contain",$class['id'])
            )))
            ->pipe(new \koolreport\processes\Map(array(
                "{value}" => function($row) {
                    $row['profession_name'] =
                        $row['profession_name'].
                        ( $this->params['show_teacher'] != null ? $row['teacher_name'] != '' ? '<br>'.$row['teacher_name'] : lang('tts.no_class') : null ).
                        ( $this->params['show_group_name'] != null ? '<br>'.$row['name'] : null ).
                        ( $this->params['show_room'] != null ? '<br>'.$row['room_name'] : null );
                    if ( $this->params['class_id'] != 0 ) {
                        $this->classList[0]['class_name'] = $row['class_name'];
                    }
                    return $row;
                }
            )))
            ->pipe(new \koolreport\processes\Map(array(
                "{end}" => function($count, $mapState) {
                    $emptyRows = [];
                    //$days = [1, 2, 3, 4, 5, 6]; //use day name if it's your case
                    foreach ($_SESSION['settings']->allowed_days as $key => $day) {
                        if ($day == 5 || $day == 6 ) {//if ($day ==true) {
                            foreach ($_SESSION['settings']->allowed_hours as $h_key => $hour) {
                                if ($hour == true) {
                                    $emptyRows[] = ['day' => $key, 'hour_num' => $h_key];
                                }
                            }
                        }
                    }
                    return $emptyRows;
                }
            )))
            ->pipe(new Cube(array(
                'row' => 'hour_num',
                'column' => 'day',
                'max' => 'profession_name'
            )))
            ->pipe(new \koolreport\processes\Map(array(
                "{value}" => function($row) {
                    foreach ($row as $k => $v)
                        if ($v == null) $row[$k] = "";
                    return $row;
                }
            )))
            ->pipe(new \koolreport\processes\Map(array(
                "{meta}" => function($meta) {
                    $colMetas = $meta["columns"];
                    foreach ($colMetas as $colKey => $colMeta) {
                        if (is_numeric($colKey)) {
                            $colMetas[$colKey]['label'] = lang("tts.day_$colKey"); //for columns '1', '2', etc
                            $colMetas[$colKey]['cssStyle'] = "width: 120px";
                        }
                        else {
                            $colMetas[$colKey]['label'] = lang("tts.$colKey"); //for column 'hour_num'
                            $colMetas[$colKey]['cssStyle'] = "width: 80px";
                        }
                    }
                    $meta["columns"] = $colMetas;
                    return $meta;
                }
            )))
            ->pipe(new \koolreport\processes\RemoveColumn(array(
                '{{all}}'
            )))
            ->pipe($this->dataStore("DS_" . $class['id']));
        }
    }
}
Sebastian Morales commented on Aug 24, 2021

I meant the report view where you use .modal class, not the report setup. If you can't provide a screenshot pls describe exactly what the problem/error is and where you load Bootstrap. Rgds,

Ron commented on Aug 25, 2021

this is the report code

<html>
<head>
    <title><?php echo lang('tts.report_class_schedule'); ?></title>
</head>
<body DIR="RTL">
    <?php
    foreach ( $this->classList as $class) {
        echo '<div class="header print-only"><img src="'.site_url('../assets/img/'.(isset($_SESSION['institute_number']) ? $_SESSION['institute_number'].'.png' : "logo.svg")).'" height="38" /></div>';
        echo '<h1 class="text-center pb-3">'. lang('tts.report_class_schedule'). ' ' .$class['class_name']. '</h1>';
        Table::create(array(
            "dataSource"=>$this->dataStore("DS_".$class['id']),
            "cssClass"=>array(
                "table"=>"table-bordered text-center",
                "th"=>"table-dark text-center",
            ),
            "sorting"=>array(
                "hour_num"=>"asc",
            )
        ));
        //echo '<div class="footer print-only">'.lang('tts.print_footer').'</div>';
        echo '<div class="page-break"></div>';
    }
    ?>
</body>
</html>

when I render the report inside my website it cause all my modal windows to stop working

Ron commented on Aug 25, 2021

In my website I use Bootstrap 4 and I have includes of CSS and JS. I have a a hidden modal dialog show when ever the page is submitted. it is a loading spinner. Once the page is rendered inside one of my pages '<BODY>' I start receiving a javascript error whenever I call the method modal('...') When the report is not rendered in the page everything works fine. as you see I don't use any package in the report so it shouldn't effect the parent container (my page body) but something is going wrong and I can't fin't the reason.

Sebastian Morales commented on Aug 26, 2021

This "modal is not a function" error could be because there're multiple instances of jQuery (Table widget always loads jQuery) or loading jQuery and Bootstrap js not in correct order. Please load jQuery first, then Bootstrap js, and add the following command just before your modal function call:

jQuery.noConflict(); // add this command
$('#myModal').modal('show');
Ron commented on Aug 26, 2021

I receive the following error: Uncaught TypeError: $ is not a function

Sebastian Morales commented on Aug 27, 2021

Did you load jQuery yourself? Pls try this:

jQuery.noConflict(); // add this command
jQuery('#myModal').modal('show');
Ron commented on Aug 27, 2021

The problem the this function call is called even before I load the rendered report. now when I use your solution I receive the error that Uncaught TypeError: $ is not a function. your solution works only after the report was rendered into the page. but I use jquery calls prior the load of the report. so if I I use your solution I need to change all the occurrences of $ on the page which does not make sense

$('#myModal').modal('show');
Sebastian Morales commented on Aug 27, 2021

For now just replace all $ with jQuery in your page to avoid conflict between loading multiple jQuery instances and Bootstrap js. We will see if we could check for existence of jQuery before loading it with KoolReport widget. Rgds,

Ron commented on Aug 27, 2021

Thanks. waiting for your update

Ron commented on Aug 31, 2021

any progress?

Sebastian Morales commented on Aug 31, 2021

Not yet, Ron. Pls keep the current solution. Or you could try this to see if it works:

jQuery.noConflict(); // add this command
$ = jQuery;
$('#myModal').modal('show');
Ron commented on Aug 31, 2021

Still gives the same error.

Ron commented on Sep 10, 2021

btw you should consider the same solution for JQUERY-UI widget. I see same happens on pages where there is a conflict with other version of JQUERY-UI

Ron commented on Sep 14, 2021

Any progress??

Sebastian Morales commented on Sep 15, 2021

Does this work for you:

$ = jQuery.noConflict(true);
$('#myModal').modal('show');

Is this only a matter of using either $ or jQuery for you? Rgds,

Ron commented on Sep 15, 2021

give the same error: utils.js:67 Uncaught TypeError: $(...).modal is not a function

Sebastian Morales commented on Sep 16, 2021

Let's try this last method:

jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
$ = jQuery; // assign alias $ to jQuery
$('#myModal').modal('show');

If this doesn't work we would have to find a way to prevent loading multiple instances of jQuery.

Ron commented on Oct 6, 2021

its not working

Ron commented on Oct 11, 2021

Any progress on this open issue. it takes a lot of time

Sebastian Morales commented on Oct 11, 2021

Are you sure to put these commands before all of your modal call:

jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery 
$ = jQuery; // assign alias $ to jQuery

One way to test it is to open your browser's dev console and run these commands;

jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
$ = jQuery; // assign alias $ to jQuery
console.log($);

If it says undefined let us know.

Ron commented on Oct 11, 2021

I get: $ is undefined Error: Uncaught TypeError: $ is not a function

Sebastian Morales commented on Oct 11, 2021

Pls try this:

jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
$ = jQuery; // assign alias $ to jQuery
console.log($);
Ron commented on Oct 11, 2021

undefined

Sebastian Morales commented on Oct 11, 2021
jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
console.log(jQuery);
Ron commented on Oct 11, 2021

returns and object of jQuery

ƒ (e,t){return new S.fn.init(e,t)}

Sebastian Morales commented on Oct 11, 2021
jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
$ = jQuery; // assign alias $ to jQuery
console.log("jQuery=", jQuery, "$ = ", $);
Ron commented on Oct 11, 2021

jQuery= ƒ (e,t){return new k.fn.init(e,t)} $ = ƒ (e,t){return new k.fn.init(e,t)}

Sebastian Morales commented on Oct 11, 2021

$ is defined now. It's essentially the same as my previous code:

jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
$ = jQuery; // assign alias $ to jQuery
console.log($);

Why did you say the result was "undefined"?

Ron commented on Oct 11, 2021

Sorry my mistake. Console.log($) = ƒ (e,t){return new k.fn.init(e,t)}

Sebastian Morales commented on Oct 11, 2021

Pls try to use $ with your modal call now (after these commands).

Ron commented on Oct 11, 2021

I made something inside my php code in order to prevent from koolreport jquery asset to be loaded. I generated a variable inside the codeigniter controller that holds the rendered report output.

$output = $report->run()->render();

Now after I have the report output in my view. I run str_replace on the $output variable and replace jquery.min.js with empty string. that we the page is working. the issue is that I receive and error message in my javascript console can't find asset url. due to the fact that the assets folder are randomly generated number I can not know the full url to remove it. I don't think that tis is the way to treat the problem. it should be handled from your side but just to show that the jquery conflict causes the issue.

Sebastian Morales commented on Oct 11, 2021

What's wrong with resolving jQuery instances conflict and assign $ again?

Ron commented on Oct 11, 2021

The function

function showLoadingModal(show) {
    jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
    $ = jQuery; // assign alias $ to jQuery
    console.log($);
    if (show == true) {
        var timeoutSeconds = 30000;
        $('#loadingModal').modal('show');
        myVar = setTimeout(function() {
            $('#loadingModal').modal('hide');
            Swal.fire({
                icon: 'error',
                title: oGlobalLanguage.error,
                text: 'הפעולה התארכה יותר מהצפוי',
                showCloseButton: true
            });
            location.reload();
        }, timeoutSeconds);
    } else {
        clearTimeout(myVar);
        setTimeout(function() {
            $('#loadingModal').modal('hide');
        }, 500);
    }
}

The output

Sebastian Morales commented on Oct 11, 2021

What's the result if you replace:

$('#loadingModal').modal('show');
...
$('#loadingModal').modal('hide');

with:

jQuery('#loadingModal').modal('show');
...
jQuery('#loadingModal').modal('hide');
Ron commented on Oct 11, 2021
function showLoadingModal(show) {
    jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
    $ = jQuery; // assign alias $ to jQuery
    console.log($);
    if (show == true) {
        var timeoutSeconds = 30000;
        //$('#loadingModal').modal('show');
        jQuery('#loadingModal').modal('show');
        myVar = setTimeout(function() {
            //$('#loadingModal').modal('hide');
            jQuery('#loadingModal').modal('hide');
            Swal.fire({
                icon: 'error',
                title: oGlobalLanguage.error,
                text: 'הפעולה התארכה יותר מהצפוי',
                showCloseButton: true
            });
            location.reload();
        }, timeoutSeconds);
    } else {
        clearTimeout(myVar);
        setTimeout(function() {
            //$('#loadingModal').modal('hide');
            jQuery('#loadingModal').modal('hide');
        }, 500);
    }
}

gives same error result like when we use $

Sebastian Morales commented on Oct 11, 2021

Pls try this:

function showLoadingModal(show) {
    jQuery.noConflict();
    if (show == true) {
        var timeoutSeconds = 30000;
        jQuery('#loadingModal').modal('show');
        ...
Ron commented on Oct 11, 2021
function showLoadingModal(show) {
    jQuery.noConflict();
    //jQuery = jQuery.noConflict(true); // relinquish alias $ from all instances of jQuery
    //$ = jQuery; // assign alias $ to jQuery
    //console.log($);
    if (show == true) {
        var timeoutSeconds = 30000;
        //$('#loadingModal').modal('show');
        jQuery('#loadingModal').modal('show');
        myVar = setTimeout(function() {
            //$('#loadingModal').modal('hide');
            jQuery('#loadingModal').modal('hide');
            Swal.fire({
                icon: 'error',
                title: oGlobalLanguage.error,
                text: 'הפעולה התארכה יותר מהצפוי',
                showCloseButton: true
            });
            location.reload();
        }, timeoutSeconds);
    } else {
        clearTimeout(myVar);
        setTimeout(function() {
            //$('#loadingModal').modal('hide');
            jQuery('#loadingModal').modal('hide');
        }, 500);
    }
}

Sebastian Morales commented on Oct 11, 2021

Yours is probably not only an issue of multiple jQuery instances but also jQuery and Bootstrap js incorrect loading order. Modal belongs to Bootstrap js, not jQuery, but Bootstrap js requires jQuery before hand. Pls make sure you must have at least one jQuery loading before Bootstrap js. If there were none jQuery before Bootstrap modal (and other Bootstrap js function) would not be available.

Ron commented on Oct 11, 2021

theses are the resource I load in my pages

<!-- jQuery + Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="<?php echo site_url('../assets/jquery/jquery-3.5.1.min.js'); ?>"></script>
    <script>window.jQuery || document.write('<script src="../assets/jquery/jquery-3.5.1.min.js"><\/script>')</script>
    <script src="<?php echo site_url('../assets/jquery/popper.min.js'); ?>"></script>
    <script src="<?php echo site_url('../assets/bootstrap/js/bootstrap-rtl.min.js'); ?>"></script>
Sebastian Morales commented on Oct 12, 2021

If you keep these jQuery and Bootstrap script src and remove all of KoolReport widgets, does modal work?

Ron commented on Oct 12, 2021

Actually I don't need to remove the Bootsrap script. the only thing that makes the issues is the koolreport jquery.min.js asset that is added once Report.js is executed in the client side. once I remove it everything works perfect. I do it on the server side using php substr_replace function to remove the jquery.min.js from the report output. doing so makes everything works fine. I think maybe you should give a parameter in the report that will enable the developer to prevent form jQuery and/or Bootstrap to be loaded in the client side

Sebastian Morales commented on Oct 12, 2021

I've checked the loading script in KoolReport.js again and it only loads jQuery if there is no jQuery instance yet. So to prevent duplication of jQuery from your side I suggest replacing your jQuery script tag:

<script src="<?php echo site_url('../assets/jquery/jquery-3.5.1.min.js'); ?>"></script>

with the following script to dynamically load your own jQuery:

<script>
function loadScript(scriptSrc) {
    var script = document.createElement('script');
    script.src = scriptSrc;
    document.head.appendChild(script); 
}
if (typeof(window.jQuery)=='undefined') loadScript("<?php echo site_url('../assets/jquery/jquery-3.5.1.min.js'); ?>");
</script>
Ron commented on Oct 12, 2021

Thanks Sebastian. actually the only line I need is

<script>window.jQuery || document.write('<script src="<?php echo site_url('../assets/jquery/jquery-3.5.1.min.js'); ?>"><\/script>')</script>

That solves the problem!

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
solved

None