Skip to content
Advertisement

Infinite Scroll won’t load more posts on scroll down when included in another file with HTML tags on top of it

I have an Infinite Scroll that loads more data (from DB) upon scrolling to the bottom,

However, when I try to include that file in another .PHP file and write any HTML tag at its top, it won’t load more posts.

On console, I get an error as

Uncaught SyntaxError: Unexpected token < in JSON at position 0

at JSON.parse (<anonymous>)
at Object.success (test.php:126)
at i (jquery-3.2.1.min.js:2)
at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2)
at A (jquery-3.2.1.min.js:4)
at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4)`

My code goes as :

getData.php

<?php

require_once('db.php');

if (! function_exists('getData')) {
    /**
     * @param int $offset
     * @param int $limit
     * @return array|null
     */
    
    function getData($offset, $limit, $conn) {
        $offset = (int)$offset;
        $limit  = (int)$limit;
        $sqlQuery = "SELECT * FROM tbl_posts ORDER BY id DESC LIMIT $limit OFFSET $offset";
        $result = mysqli_query($conn, $sqlQuery);
        $rows = [];
        while ($row = mysqli_fetch_assoc($result)) {
            $cleanRow = [];
            foreach ($row as $column => $value) {
                $cleanRow[$column] = htmlentities($value);
            }
            $rows[]= $cleanRow;
        }
        return $rows;
    }
}

Index.php

<?php
require_once ('getData.php');

$offset = (int)($_GET['offset'] ?? 0);
$dataOnly = (int)($_GET['dataOnly'] ?? 0);
$limit  = 7;
$rows = getData($offset, $limit, $conn);
$offset+= $limit;
$data = [
    'rows'   => $rows,
    'offset' => $offset,
];


$data = json_encode($data);

// if this is an ajax call, stop here and just spit out our json
if ($dataOnly) {
    echo $data;
    exit;
}
// otherwise, render the page
$sqlQuery = "SELECT * FROM tbl_posts";
$result = mysqli_query($conn, $sqlQuery);
$total_count = mysqli_num_rows($result);
?>

    <script type="text/javascript" src="jquery-3.2.1.min.js"></script>
    <style type="text/css">
        body {
            font-family: Arial;
            background: #e9ebee;
            font-size: 0.9em;
        }

        .post-wall {
            background: #FFF;
            border: #e0dfdf 1px solid;
            padding: 20px;
            border-radius: 5px;
            margin: 0 auto;
            width: 500px;
        }

        .post-item {
            padding: 10px;
            border: #f3f3f3 1px solid;
            border-radius: 5px;
            margin-bottom: 30px;
        }

        .post-title {
            color: #4faae6;
        }

        .ajax-loader {
            display: block;
            text-align: center;
        }
        .ajax-loader img {
            width: 50px;
            vertical-align: middle;
        }
    </style>
<div class="post-wall">
    <div id="post-list">
        <input type="hidden" name="total_count" id="total_count" value="<?= $total_count ?>" />
        <input type="hidden" name="offset" id="offset" value="<?= $offset ?>" />
    </div>
    <div class="ajax-loader text-center">
        <img src="LoaderIcon.gif"> Loading more posts...
    </div>
</div>

<script type="text/javascript">
    $(document).ready(function(){
        // load the initial rows on page load
        let initialData = <?= $data ?? '' ?>;
        if (initialData) {
            if (initialData.rows) {
                addrows(initialData.rows);
                $('.ajax-loader').hide();
            }
        }
        windowOnScroll();

    });
    function windowOnScroll() {
    $(window).on("scroll", function(e) {
      if ($(window).scrollTop() + 1 >= $(document).height() - $(window).height()) {
        if ($(".post-item").length < $("#total_count").val()) {
          let offset = $('#offset').val();
          getMoreData(offset)
        }
      }
    });
  }

    function getMoreData(offset) {
        $('.ajax-loader').show();
        $(window).off("scroll");
        let pageUrl = window.location.href.split('?')[0];
        $.ajax({
            url: pageUrl + '?dataOnly=1&offset=' + offset,
            type: "get",
            
            success: function (response) {
            response = JSON.parse(response);
            if (response.rows) {
            addrows(response.rows);
            if (response.offset) {
            $('#offset').val(response.offset);
            }
            $('.ajax-loader').hide();
            }
            windowOnScroll();
            }
        });
    }

    function addrows(rows) {
        let postList = $("#post-list");
        $.each(rows, function (i, row) {
            let rowHtml = '<div class="post-item" id="'+row.id+'"><p class="post-title">'+row.title+'</p><p>'+row.content+'</p></div>';
            postList.append(rowHtml);
        });
    }
</script>

Now please note that the above code works completely fine, as infinite scroll does exactly what it needs to be. But when I place it inside another file like

test.php

<div>
<?php include("index.php"); ?>
</div> 

the first few posts (7) load and along with the loader.gif at the bottom. That’s all.

Any help is greatly appreciated.

Advertisement

Answer

After basic understanding on what the error is trying to say, I finally figured out this as

ERROR:

Uncaught SyntaxError: Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at Object.success (test.php:126)
at i (jquery-3.2.1.min.js:2)
at Object.fireWith [as resolveWith] (jquery-3.2.1.min.js:2)
at A (jquery-3.2.1.min.js:4)
at XMLHttpRequest.<anonymous> (jquery-3.2.1.min.js:4)

JSON should start with a valid JSON value – an object, array, string, number, or false/true/null. This response started with a < (hence the “Unexpected token <”).

That unexpected token, <, is a strong clue that the response was HTML instead of JSON.

The root cause is that the server returned HTML or some other non-JSON string.

So what I did was, just simply cut the JSON code into the top of the test.php leaving everything as it is.

index.php

 <script type="text/javascript" src="jquery-3.2.1.min.js"></script>
    <style type="text/css">
        body {
            font-family: Arial;
            background: #e9ebee;
            font-size: 0.9em;
        }

        .post-wall {
            background: #FFF;
            border: #e0dfdf 1px solid;
            padding: 20px;
            border-radius: 5px;
            margin: 0 auto;
            width: 500px;
        }

        .post-item {
            padding: 10px;
            border: #f3f3f3 1px solid;
            border-radius: 5px;
            margin-bottom: 30px;
        }

        .post-title {
            color: #4faae6;
        }

        .ajax-loader {
            display: block;
            text-align: center;
        }
        .ajax-loader img {
            width: 50px;
            vertical-align: middle;
        }
    </style>
<div class="post-wall">
    <div id="post-list">
        <input type="hidden" name="total_count" id="total_count" value="<?= $total_count ?>" />
        <input type="hidden" name="offset" id="offset" value="<?= $offset ?>" />
    </div>
    <div class="ajax-loader text-center">
        <img src="LoaderIcon.gif"> Loading more posts...
    </div>
</div>

<script type="text/javascript">
    $(document).ready(function(){
        // load the initial rows on page load
        let initialData = <?= $data ?? '' ?>;
        if (initialData) {
            if (initialData.rows) {
                addrows(initialData.rows);
                $('.ajax-loader').hide();
            }
        }
        windowOnScroll();

    });
    function windowOnScroll() {
    $(window).on("scroll", function(e) {
      if ($(window).scrollTop() + 1 >= $(document).height() - $(window).height()) {
        if ($(".post-item").length < $("#total_count").val()) {
          let offset = $('#offset').val();
          getMoreData(offset)
        }
      }
    });
  }

    function getMoreData(offset) {
        $('.ajax-loader').show();
        $(window).off("scroll");
        let pageUrl = window.location.href.split('?')[0];
        $.ajax({
            url: pageUrl + '?dataOnly=1&offset=' + offset,
            type: "get",
            
            success: function (response) {
            response = JSON.parse(response);
            if (response.rows) {
            addrows(response.rows);
            if (response.offset) {
            $('#offset').val(response.offset);
            }
            $('.ajax-loader').hide();
            }
            windowOnScroll();
            }
        });
    }

    function addrows(rows) {
        let postList = $("#post-list");
        $.each(rows, function (i, row) {
            let rowHtml = '<div class="post-item" id="'+row.id+'"><p class="post-title">'+row.title+'</p><p>'+row.content+'</p></div>';
            postList.append(rowHtml);
        });
    }
</script>

test.php

<?php
require_once ('getData.php');

$offset = (int)($_GET['offset'] ?? 0);
$dataOnly = (int)($_GET['dataOnly'] ?? 0);
$limit  = 7;
$rows = getData($offset, $limit, $conn);
$offset+= $limit;
$data = [
    'rows'   => $rows,
    'offset' => $offset,
];


$data = json_encode($data);

// if this is an ajax call, stop here and just spit out our json
if ($dataOnly) {
    echo $data;
    exit;
}
// otherwise, render the page
$sqlQuery = "SELECT * FROM tbl_posts";
$result = mysqli_query($conn, $sqlQuery);
$total_count = mysqli_num_rows($result);
?>

<div class="some">
<?PHP include("index.php"); ?>
</div>

And Voila. It works perfectly fine.

Thanks to @WesleySmith & @AngelDeykov for the time they spared on this.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement