Welcome Guest, Not a member yet? Register   Sign In
AJAX post request gives 404 Page Not Found Error.
#1

(This post was last modified: 06-13-2022, 12:44 PM by AgBRAT.)

I have developed a site where users can upload images of shapes, like/dislike/favorite/comment, subscribe to other users, and keep a view history of pages users have visited. As such, I have a pretty lengthy JQuery script that handles all of this for a single image view. A month ago, I revamped my entire file structure which caused the whole site to break. I finally have the rest of the site back up and running (better than before) except I cannot figure out how to get these darn Ajax post requests to work again. Again... 

I am getting a 404 Page Not Found error when I inspect the page using Firefox Developers Browser. So I am guessing the URL bit is what's not correct. I have tried all manner of combinations of site_url, base_url, leading "/", no leading "/", and even named routes but I cannot get it right. 

The post request is handled by App\Controllers\Images\Gallery::view_image 
PHP Code:
public function view_image(string $viewkey
    {
        if ($this->request->IsAjax()) {

            if (! empty($this->request->getPost('action')) && ! empty($this->request->getPost('viewkey')) && ! empty(session()->get('username'))) {

                $input = [];

                $input = [
                    'action'    => $this->request->getPost('action'),
                    'username' => session()->get('username'),
                    'viewkey'  => $this->request->getPost('viewkey'),
                    'modified'  => date('Y-m-d H:i:s'),
                ];

                $actionCount $this->actionModel->insertAction($input);

                return $actionCount;
            
            


            if ('post' == $this->request->getMethod() && $this->request->getPost('comment_text')) {

                $parentID $this->request->getPost('reply_id');
                $commentText $this->request->getPost('comment_text');
                $username session()->get('username');

                $data = [
                    'viewkey'    => $this->request->getPost('content_id'),
                    'comment_text'  => $this->commentModel->escapeString($commentText),
                    'parent_id'    => $parentID,
                    'modified'      => date('Y-m-d H:i:s'),
                    'username'      => $username,
                ];

                $resp $this->commentModel->insertComment($data);


                if ($resp != NULL) {

                    foreach ($resp as $row) {

                        $date get_date_words($row->modifieddate('Y-m-d H:i:s'));

                        echo "<li id=\"li-comment-{$row->comment_id}\">" .
                        "<div><span class=\"username\">{$row->username}</span></div>" .
                        "<div style=\"margin-top:4px;\">{$row->comment_text}</div>" .
                        "<div><span class=\"modified\">{$date}</span></div>" .
                        "<a href=\"#\" class=\"reply-button\" id=\"{$row->comment_id}\">reply</a>" .
                        "</li>";
                    }

                } else {

                    echo 'Error in adding comment';
                }
            
            
} else {

                echo 'Error: Please enter your comment';
            }
        

        $image $this->imageModel->fillImageEntity($viewkey);

        $data = [];

        $data = [
            'image'        => $image,
            'title'        => $image->title,
            'imageComments' => $this->commentModel->getComments($viewkey),
            'script'        => 'js/image_action',
        ];

        echo view('templates/header'$data);
        echo view('templates/navigation'$data);
        echo view('images/view_image'$data);
        echo view('templates/footer'$data);
    

The Ajax file itself is as follows (don't mind the url not matching in each request I was experimenting with the view count request first):
PHP Code:
<script>
    
    
$(document).ready(function() {  
        
var csrfName "<?= csrf_token(); ?>";
        var csrfHash "<?= csrf_hash(); ?>"
        var viewkey "<?= esc($image->viewkey); ?>";

        // If user views image (on page refresh)
        $.ajax({
            type"post",
            url"<?= base_url('/images/gallery/view_image'); ?>",
            dataType"json",
            data: {
                [csrfName]: csrfHash,
                "viewkey"viewkey,
                "action"'view',
            },
            headers: {
                'X-Requested-With''XMLHttpRequest',
            },
            success: function(data) {
                var res data;
                csrfName data.csrfName;
                csrfHash data.csrfHash;

                // display number of views
                $('span.views').text(res.views);
            }
        });

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action "unlike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action "undislike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });
        // if the user clicks on the favorite button
        $(".favorite-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-regular fa-heart")) {
                action "favorite";
            } else if ($clicked_btn.hasClass("fa-solid fa-heart")) {
                action "unfavorite";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "favorite") {
                        $clicked_btn.removeClass("fa-regular fa-heart");
                        $clicked_btn.addClass("fa-solid fa-heart");
                    } else if (action == "unfavorite") {
                        $clicked_btn.removeClass("fa-solid fa-heart");
                        $clicked_btn.addClass("fa-regular fa-heart");
                    }

                    // display number of favorites
                    $clicked_btn.siblings('span.favorites').text(res.favorites);
                }
            });
        });

        // If user clicks the subscribe button
        $(".subscribe").on("click", function () {
            var userProfile = $(this).data("user");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-solid fa-rss")) {
                action "subscribe";
            } else if ($clicked_btn.hasClass("fa-solid fa-user-check")) {
                action "unsubscribe";
            }

            $.ajax ({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "user_profile"userProfile,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "subscribe") {
                        $clicked_btn.removeClass("fa-solid fa-rss");
                        $clicked_btn.addClass("fa-solid fa-user-check");
                    } else if (action == "unsubscribe") {
                        $clicked_btn.removeClass("fa-solid fa-user-check");
                        $clicked_btn.addClass("fa-solid fa-rss");
                    }
                }
            });
        });

        $("#cancel-comment-reply-link").hide();

        $(".reply-button").on('click', function(event) {
            event.preventDefault();
            var id = $(this).attr("id");

            if ($("#li-comment-" id).find('ul').length 0) {
                $("#li-comment-" id " ul:first").prepend($("#comment-form-wrapper"));
            } else {
                $("#li-comment-" id).append($("#comment-form-wrapper"));
            }

            $("#reply-id").attr("value"id);
            $("#cancel-comment-reply-link").show();
        });

        $("#cancel-comment-reply-link").bind("click", function(event) {
            event.preventDefault();
            $("#reply-id").attr("value""");
            $("#comment-object").prepend($("#comment-form-wrapper"));
            $(this).hide();
        });

        $("#comment-form").bind("submit", function(event) {
            event.preventDefault();

            if ($("#comment-text").val() == "") {
                alert("Please enter your comment");
                return false;
            }

            $.ajax({
                type"post",
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                data: $('#comment-form').serialize() + "&" + [csrfName] + "=" csrfHash,
                dataType'html',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                beforeSend: function () {
                    $('#comment-object').block({
                        message"Please wait...",
                        css: {
                            border'none',
                            padding'15px',
                            backgroundColor'#ccc',
                            '-webkit-border-radius''10px',
                            '-moz-border-radius''10px',
                        },
                        overlayCSS: {
                            backgroundColor'#ffe'
                        },
                    });
                },
                success: function (comment) {
                    var replyID = $("#reply-id").val();

                    if (replyID == "") {
                        $("#comment-object ul:first").prepend(comment);

                        if (comment.toLowerCase().indexOf("error") >= 0) {
                            $("#comment-resp-err").attr("value"comment);
                        }
                    } else {

                        if ($("#li-comment-" replyID).find('ul').length 0) {
                            $("#li-comment-" replyID).append('<ul class="comment-text">' comment '</ul>');
                        }
                    }
                    $("#comment-text").attr("value""");
                    $("#reply-id").attr("value""");
                    $("#cancel-comment-reply-link").hide();
                    $("#comment-object").prepend($("#comment-form-wrapper"));
                    $("#comment-object").unblock();
                }
            });
        });
    });
</
script

I have defined a route for both get (for the view itself) and post (for the Ajax request).
PHP Code:
// Images Routes
$routes->group('images', ['filter' => 'auth'], function ($routes) {
    $routes->get('gallery''Images\Gallery::index', ['as' => 'gallery']);
    $routes->get('view_image/(:alphanum)''Images\Gallery::view_image/$1', ['as' => 'view_image']);
    $routes->post('view_image''Images\Gallery::view_image');
}); 

(06-13-2022, 12:22 PM)AgBRAT Wrote: I have developed a site where users can upload images of shapes, like/dislike/favorite/comment, subscribe to other users, and keep a view history of pages users have visited. As such, I have a pretty lengthy JQuery script that handles all of this for a single image view. A month ago, I revamped my entire file structure which caused the whole site to break. I finally have the rest of the site back up and running (better than before) except I cannot figure out how to get these darn Ajax post requests to work again. Again... 

I am getting a 404 Page Not Found error when I inspect the page using Firefox Developers Browser. So I am guessing the URL bit is what's not correct. I have tried all manner of combinations of site_url, base_url, leading "/", no leading "/", and even named routes but I cannot get it right. 

The post request is handled by App\Controllers\Images\Gallery::view_image 
PHP Code:
public function view_image(string $viewkey
    {
        if ($this->request->IsAjax()) {

            if (! empty($this->request->getPost('action')) && ! empty($this->request->getPost('viewkey')) && ! empty(session()->get('username'))) {

                $input = [];

                $input = [
                    'action'    => $this->request->getPost('action'),
                    'username' => session()->get('username'),
                    'viewkey'  => $this->request->getPost('viewkey'),
                    'modified'  => date('Y-m-d H:i:s'),
                ];

                $actionCount $this->actionModel->insertAction($input);

                return $actionCount;
            
            


            if ('post' == $this->request->getMethod() && $this->request->getPost('comment_text')) {

                $parentID $this->request->getPost('reply_id');
                $commentText $this->request->getPost('comment_text');
                $username session()->get('username');

                $data = [
                    'viewkey'    => $this->request->getPost('content_id'),
                    'comment_text'  => $this->commentModel->escapeString($commentText),
                    'parent_id'    => $parentID,
                    'modified'      => date('Y-m-d H:i:s'),
                    'username'      => $username,
                ];

                $resp $this->commentModel->insertComment($data);


                if ($resp != NULL) {

                    foreach ($resp as $row) {

                        $date get_date_words($row->modifieddate('Y-m-d H:i:s'));

                        echo "<li id=\"li-comment-{$row->comment_id}\">" .
                        "<div><span class=\"username\">{$row->username}</span></div>" .
                        "<div style=\"margin-top:4px;\">{$row->comment_text}</div>" .
                        "<div><span class=\"modified\">{$date}</span></div>" .
                        "<a href=\"#\" class=\"reply-button\" id=\"{$row->comment_id}\">reply</a>" .
                        "</li>";
                    }

                } else {

                    echo 'Error in adding comment';
                }
            
            
} else {

                echo 'Error: Please enter your comment';
            }
        

        $image $this->imageModel->fillImageEntity($viewkey);

        $data = [];

        $data = [
            'image'        => $image,
            'title'        => $image->title,
            'imageComments' => $this->commentModel->getComments($viewkey),
            'script'        => 'js/image_action',
        ];

        echo view('templates/header'$data);
        echo view('templates/navigation'$data);
        echo view('images/view_image'$data);
        echo view('templates/footer'$data);
    

The Ajax file itself is as follows (don't mind the url not matching in each request I was experimenting with the view count request first):
PHP Code:
<script>
    
    
$(document).ready(function() {  
        
var csrfName "<?= csrf_token(); ?>";
        var csrfHash "<?= csrf_hash(); ?>"
        var viewkey "<?= esc($image->viewkey); ?>";

        // If user views image (on page refresh)
        $.ajax({
            type"post",
            url"<?= base_url('/images/gallery/view_image'); ?>",
            dataType"json",
            data: {
                [csrfName]: csrfHash,
                "viewkey"viewkey,
                "action"'view',
            },
            headers: {
                'X-Requested-With''XMLHttpRequest',
            },
            success: function(data) {
                var res data;
                csrfName data.csrfName;
                csrfHash data.csrfHash;

                // display number of views
                $('span.views').text(res.views);
            }
        });

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action "unlike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action "undislike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });
        // if the user clicks on the favorite button
        $(".favorite-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-regular fa-heart")) {
                action "favorite";
            } else if ($clicked_btn.hasClass("fa-solid fa-heart")) {
                action "unfavorite";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "favorite") {
                        $clicked_btn.removeClass("fa-regular fa-heart");
                        $clicked_btn.addClass("fa-solid fa-heart");
                    } else if (action == "unfavorite") {
                        $clicked_btn.removeClass("fa-solid fa-heart");
                        $clicked_btn.addClass("fa-regular fa-heart");
                    }

                    // display number of favorites
                    $clicked_btn.siblings('span.favorites').text(res.favorites);
                }
            });
        });

        // If user clicks the subscribe button
        $(".subscribe").on("click", function () {
            var userProfile = $(this).data("user");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-solid fa-rss")) {
                action "subscribe";
            } else if ($clicked_btn.hasClass("fa-solid fa-user-check")) {
                action "unsubscribe";
            }

            $.ajax ({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "user_profile"userProfile,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "subscribe") {
                        $clicked_btn.removeClass("fa-solid fa-rss");
                        $clicked_btn.addClass("fa-solid fa-user-check");
                    } else if (action == "unsubscribe") {
                        $clicked_btn.removeClass("fa-solid fa-user-check");
                        $clicked_btn.addClass("fa-solid fa-rss");
                    }
                }
            });
        });

        $("#cancel-comment-reply-link").hide();

        $(".reply-button").on('click', function(event) {
            event.preventDefault();
            var id = $(this).attr("id");

            if ($("#li-comment-" id).find('ul').length 0) {
                $("#li-comment-" id " ul:first").prepend($("#comment-form-wrapper"));
            } else {
                $("#li-comment-" id).append($("#comment-form-wrapper"));
            }

            $("#reply-id").attr("value"id);
            $("#cancel-comment-reply-link").show();
        });

        $("#cancel-comment-reply-link").bind("click", function(event) {
            event.preventDefault();
            $("#reply-id").attr("value""");
            $("#comment-object").prepend($("#comment-form-wrapper"));
            $(this).hide();
        });

        $("#comment-form").bind("submit", function(event) {
            event.preventDefault();

            if ($("#comment-text").val() == "") {
                alert("Please enter your comment");
                return false;
            }

            $.ajax({
                type"post",
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                data: $('#comment-form').serialize() + "&" + [csrfName] + "=" csrfHash,
                dataType'html',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                beforeSend: function () {
                    $('#comment-object').block({
                        message"Please wait...",
                        css: {
                            border'none',
                            padding'15px',
                            backgroundColor'#ccc',
                            '-webkit-border-radius''10px',
                            '-moz-border-radius''10px',
                        },
                        overlayCSS: {
                            backgroundColor'#ffe'
                        },
                    });
                },
                success: function (comment) {
                    var replyID = $("#reply-id").val();

                    if (replyID == "") {
                        $("#comment-object ul:first").prepend(comment);

                        if (comment.toLowerCase().indexOf("error") >= 0) {
                            $("#comment-resp-err").attr("value"comment);
                        }
                    } else {

                        if ($("#li-comment-" replyID).find('ul').length 0) {
                            $("#li-comment-" replyID).append('<ul class="comment-text">' comment '</ul>');
                        }
                    }
                    $("#comment-text").attr("value""");
                    $("#reply-id").attr("value""");
                    $("#cancel-comment-reply-link").hide();
                    $("#comment-object").prepend($("#comment-form-wrapper"));
                    $("#comment-object").unblock();
                }
            });
        });
    });
</
script

I have defined a route for both get (for the view itself) and post (for the Ajax request).
PHP Code:
// Images Routes
$routes->group('images', ['filter' => 'auth'], function ($routes) {
    $routes->get('gallery''Images\Gallery::index', ['as' => 'gallery']);
    $routes->get('view_image/(:alphanum)''Images\Gallery::view_image/$1', ['as' => 'view_image']);
    $routes->post('view_image''Images\Gallery::view_image');
}); 

So I figured out the URL:
PHP Code:
url"<?= base_url(); ?>/images/view_image/<?= $image->viewkey;?>"
Reply
#2

(06-13-2022, 12:22 PM)AgBRAT Wrote: I have developed a site where users can upload images of shapes, like/dislike/favorite/comment, subscribe to other users, and keep a view history of pages users have visited. As such, I have a pretty lengthy JQuery script that handles all of this for a single image view. A month ago, I revamped my entire file structure which caused the whole site to break. I finally have the rest of the site back up and running (better than before) except I cannot figure out how to get these darn Ajax post requests to work again. Again... 

I am getting a 404 Page Not Found error when I inspect the page using Firefox Developers Browser. So I am guessing the URL bit is what's not correct. I have tried all manner of combinations of site_url, base_url, leading "/", no leading "/", and even named routes but I cannot get it right. 

The post request is handled by App\Controllers\Images\Gallery::view_image 
PHP Code:
public function view_image(string $viewkey
    {
        if ($this->request->IsAjax()) {

            if (! empty($this->request->getPost('action')) && ! empty($this->request->getPost('viewkey')) && ! empty(session()->get('username'))) {

                $input = [];

                $input = [
                    'action'    => $this->request->getPost('action'),
                    'username' => session()->get('username'),
                    'viewkey'  => $this->request->getPost('viewkey'),
                    'modified'  => date('Y-m-d H:i:s'),
                ];

                $actionCount $this->actionModel->insertAction($input);

                return $actionCount;
            
            


            if ('post' == $this->request->getMethod() && $this->request->getPost('comment_text')) {

                $parentID $this->request->getPost('reply_id');
                $commentText $this->request->getPost('comment_text');
                $username session()->get('username');

                $data = [
                    'viewkey'    => $this->request->getPost('content_id'),
                    'comment_text'  => $this->commentModel->escapeString($commentText),
                    'parent_id'    => $parentID,
                    'modified'      => date('Y-m-d H:i:s'),
                    'username'      => $username,
                ];

                $resp $this->commentModel->insertComment($data);


                if ($resp != NULL) {

                    foreach ($resp as $row) {

                        $date get_date_words($row->modifieddate('Y-m-d H:i:s'));

                        echo "<li id=\"li-comment-{$row->comment_id}\">" .
                        "<div><span class=\"username\">{$row->username}</span></div>" .
                        "<div style=\"margin-top:4px;\">{$row->comment_text}</div>" .
                        "<div><span class=\"modified\">{$date}</span></div>" .
                        "<a href=\"#\" class=\"reply-button\" id=\"{$row->comment_id}\">reply</a>" .
                        "</li>";
                    }

                } else {

                    echo 'Error in adding comment';
                }
            
            
} else {

                echo 'Error: Please enter your comment';
            }
        

        $image $this->imageModel->fillImageEntity($viewkey);

        $data = [];

        $data = [
            'image'        => $image,
            'title'        => $image->title,
            'imageComments' => $this->commentModel->getComments($viewkey),
            'script'        => 'js/image_action',
        ];

        echo view('templates/header'$data);
        echo view('templates/navigation'$data);
        echo view('images/view_image'$data);
        echo view('templates/footer'$data);
    

The Ajax file itself is as follows (don't mind the url not matching in each request I was experimenting with the view count request first):
PHP Code:
<script>
    
    
$(document).ready(function() {  
        
var csrfName "<?= csrf_token(); ?>";
        var csrfHash "<?= csrf_hash(); ?>"
        var viewkey "<?= esc($image->viewkey); ?>";

        // If user views image (on page refresh)
        $.ajax({
            type"post",
            url"<?= base_url('/images/gallery/view_image'); ?>",
            dataType"json",
            data: {
                [csrfName]: csrfHash,
                "viewkey"viewkey,
                "action"'view',
            },
            headers: {
                'X-Requested-With''XMLHttpRequest',
            },
            success: function(data) {
                var res data;
                csrfName data.csrfName;
                csrfHash data.csrfHash;

                // display number of views
                $('span.views').text(res.views);
            }
        });

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action "unlike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action "undislike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });
        // if the user clicks on the favorite button
        $(".favorite-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-regular fa-heart")) {
                action "favorite";
            } else if ($clicked_btn.hasClass("fa-solid fa-heart")) {
                action "unfavorite";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "favorite") {
                        $clicked_btn.removeClass("fa-regular fa-heart");
                        $clicked_btn.addClass("fa-solid fa-heart");
                    } else if (action == "unfavorite") {
                        $clicked_btn.removeClass("fa-solid fa-heart");
                        $clicked_btn.addClass("fa-regular fa-heart");
                    }

                    // display number of favorites
                    $clicked_btn.siblings('span.favorites').text(res.favorites);
                }
            });
        });

        // If user clicks the subscribe button
        $(".subscribe").on("click", function () {
            var userProfile = $(this).data("user");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-solid fa-rss")) {
                action "subscribe";
            } else if ($clicked_btn.hasClass("fa-solid fa-user-check")) {
                action "unsubscribe";
            }

            $.ajax ({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "user_profile"userProfile,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "subscribe") {
                        $clicked_btn.removeClass("fa-solid fa-rss");
                        $clicked_btn.addClass("fa-solid fa-user-check");
                    } else if (action == "unsubscribe") {
                        $clicked_btn.removeClass("fa-solid fa-user-check");
                        $clicked_btn.addClass("fa-solid fa-rss");
                    }
                }
            });
        });

        $("#cancel-comment-reply-link").hide();

        $(".reply-button").on('click', function(event) {
            event.preventDefault();
            var id = $(this).attr("id");

            if ($("#li-comment-" id).find('ul').length 0) {
                $("#li-comment-" id " ul:first").prepend($("#comment-form-wrapper"));
            } else {
                $("#li-comment-" id).append($("#comment-form-wrapper"));
            }

            $("#reply-id").attr("value"id);
            $("#cancel-comment-reply-link").show();
        });

        $("#cancel-comment-reply-link").bind("click", function(event) {
            event.preventDefault();
            $("#reply-id").attr("value""");
            $("#comment-object").prepend($("#comment-form-wrapper"));
            $(this).hide();
        });

        $("#comment-form").bind("submit", function(event) {
            event.preventDefault();

            if ($("#comment-text").val() == "") {
                alert("Please enter your comment");
                return false;
            }

            $.ajax({
                type"post",
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                data: $('#comment-form').serialize() + "&" + [csrfName] + "=" csrfHash,
                dataType'html',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                beforeSend: function () {
                    $('#comment-object').block({
                        message"Please wait...",
                        css: {
                            border'none',
                            padding'15px',
                            backgroundColor'#ccc',
                            '-webkit-border-radius''10px',
                            '-moz-border-radius''10px',
                        },
                        overlayCSS: {
                            backgroundColor'#ffe'
                        },
                    });
                },
                success: function (comment) {
                    var replyID = $("#reply-id").val();

                    if (replyID == "") {
                        $("#comment-object ul:first").prepend(comment);

                        if (comment.toLowerCase().indexOf("error") >= 0) {
                            $("#comment-resp-err").attr("value"comment);
                        }
                    } else {

                        if ($("#li-comment-" replyID).find('ul').length 0) {
                            $("#li-comment-" replyID).append('<ul class="comment-text">' comment '</ul>');
                        }
                    }
                    $("#comment-text").attr("value""");
                    $("#reply-id").attr("value""");
                    $("#cancel-comment-reply-link").hide();
                    $("#comment-object").prepend($("#comment-form-wrapper"));
                    $("#comment-object").unblock();
                }
            });
        });
    });
</
script

I have defined a route for both get (for the view itself) and post (for the Ajax request).
PHP Code:
// Images Routes
$routes->group('images', ['filter' => 'auth'], function ($routes) {
    $routes->get('gallery''Images\Gallery::index', ['as' => 'gallery']);
    $routes->get('view_image/(:alphanum)''Images\Gallery::view_image/$1', ['as' => 'view_image']);
    $routes->post('view_image''Images\Gallery::view_image');
}); 

(06-13-2022, 12:22 PM)AgBRAT Wrote: I have developed a site where users can upload images of shapes, like/dislike/favorite/comment, subscribe to other users, and keep a view history of pages users have visited. As such, I have a pretty lengthy JQuery script that handles all of this for a single image view. A month ago, I revamped my entire file structure which caused the whole site to break. I finally have the rest of the site back up and running (better than before) except I cannot figure out how to get these darn Ajax post requests to work again. Again... 

I am getting a 404 Page Not Found error when I inspect the page using Firefox Developers Browser. So I am guessing the URL bit is what's not correct. I have tried all manner of combinations of site_url, base_url, leading "/", no leading "/", and even named routes but I cannot get it right. 

The post request is handled by App\Controllers\Images\Gallery::view_image 
PHP Code:
public function view_image(string $viewkey
    {
        if ($this->request->IsAjax()) {

            if (! empty($this->request->getPost('action')) && ! empty($this->request->getPost('viewkey')) && ! empty(session()->get('username'))) {

                $input = [];

                $input = [
                    'action'    => $this->request->getPost('action'),
                    'username' => session()->get('username'),
                    'viewkey'  => $this->request->getPost('viewkey'),
                    'modified'  => date('Y-m-d H:i:s'),
                ];

                $actionCount $this->actionModel->insertAction($input);

                return $actionCount;
            
            


            if ('post' == $this->request->getMethod() && $this->request->getPost('comment_text')) {

                $parentID $this->request->getPost('reply_id');
                $commentText $this->request->getPost('comment_text');
                $username session()->get('username');

                $data = [
                    'viewkey'    => $this->request->getPost('content_id'),
                    'comment_text'  => $this->commentModel->escapeString($commentText),
                    'parent_id'    => $parentID,
                    'modified'      => date('Y-m-d H:i:s'),
                    'username'      => $username,
                ];

                $resp $this->commentModel->insertComment($data);


                if ($resp != NULL) {

                    foreach ($resp as $row) {

                        $date get_date_words($row->modifieddate('Y-m-d H:i:s'));

                        echo "<li id=\"li-comment-{$row->comment_id}\">" .
                        "<div><span class=\"username\">{$row->username}</span></div>" .
                        "<div style=\"margin-top:4px;\">{$row->comment_text}</div>" .
                        "<div><span class=\"modified\">{$date}</span></div>" .
                        "<a href=\"#\" class=\"reply-button\" id=\"{$row->comment_id}\">reply</a>" .
                        "</li>";
                    }

                } else {

                    echo 'Error in adding comment';
                }
            
            
} else {

                echo 'Error: Please enter your comment';
            }
        

        $image $this->imageModel->fillImageEntity($viewkey);

        $data = [];

        $data = [
            'image'        => $image,
            'title'        => $image->title,
            'imageComments' => $this->commentModel->getComments($viewkey),
            'script'        => 'js/image_action',
        ];

        echo view('templates/header'$data);
        echo view('templates/navigation'$data);
        echo view('images/view_image'$data);
        echo view('templates/footer'$data);
    

The Ajax file itself is as follows (don't mind the url not matching in each request I was experimenting with the view count request first):
PHP Code:
<script>
    
    
$(document).ready(function() {  
        
var csrfName "<?= csrf_token(); ?>";
        var csrfHash "<?= csrf_hash(); ?>"
        var viewkey "<?= esc($image->viewkey); ?>";

        // If user views image (on page refresh)
        $.ajax({
            type"post",
            url"<?= base_url('/images/gallery/view_image'); ?>",
            dataType"json",
            data: {
                [csrfName]: csrfHash,
                "viewkey"viewkey,
                "action"'view',
            },
            headers: {
                'X-Requested-With''XMLHttpRequest',
            },
            success: function(data) {
                var res data;
                csrfName data.csrfName;
                csrfHash data.csrfHash;

                // display number of views
                $('span.views').text(res.views);
            }
        });

        // if the user clicks on the like button
        $(".like-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-up")) {
                action "like";
            } else if ($clicked_btn.hasClass("fa-thumbs-up")) {
                action "unlike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "like") {
                        $clicked_btn.removeClass("fa-thumbs-o-up");
                        $clicked_btn.addClass("fa-thumbs-up");
                    } else if (action == "unlike") {
                        $clicked_btn.removeClass("fa-thumbs-up");
                        $clicked_btn.addClass("fa-thumbs-o-up");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-down").removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down");
                }
            });
        });
        // If the user clicks on the dislike button
        $(".dislike-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-thumbs-o-down")) {
                action "dislike";
            } else if ($clicked_btn.hasClass("fa-thumbs-down")) {
                action "undislike";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "dislike") {
                        $clicked_btn.removeClass("fa-thumbs-o-down");
                        $clicked_btn.addClass("fa-thumbs-down");
                    } else if (action == "undislike") {
                        $clicked_btn.removeClass("fa-thumbs-down");
                        $clicked_btn.addClass("fa-thumbs-o-down");
                    }

                    // display number of likes and dislikes
                    $clicked_btn.siblings('span.likes').text(res.likes);
                    $clicked_btn.siblings('span.dislikes').text(res.dislikes);

                    // Change button styling of the other button if user is reacting the second time to image
                    $clicked_btn.siblings("i.fa-thumbs-up").removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up");
                }
            });
        });
        // if the user clicks on the favorite button
        $(".favorite-button").on("click", function() {
            var viewkey = $(this).data("viewkey");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-regular fa-heart")) {
                action "favorite";
            } else if ($clicked_btn.hasClass("fa-solid fa-heart")) {
                action "unfavorite";
            }

            $.ajax({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "viewkey"viewkey
                
},
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "favorite") {
                        $clicked_btn.removeClass("fa-regular fa-heart");
                        $clicked_btn.addClass("fa-solid fa-heart");
                    } else if (action == "unfavorite") {
                        $clicked_btn.removeClass("fa-solid fa-heart");
                        $clicked_btn.addClass("fa-regular fa-heart");
                    }

                    // display number of favorites
                    $clicked_btn.siblings('span.favorites').text(res.favorites);
                }
            });
        });

        // If user clicks the subscribe button
        $(".subscribe").on("click", function () {
            var userProfile = $(this).data("user");
            $clicked_btn = $(this);

            if ($clicked_btn.hasClass("fa-solid fa-rss")) {
                action "subscribe";
            } else if ($clicked_btn.hasClass("fa-solid fa-user-check")) {
                action "unsubscribe";
            }

            $.ajax ({
                url"<?= route_to('view_image', $image->viewkey); ?>",
                type"post",
                dataType"json",
                data: {
                    [csrfName]: csrfHash,
                    "action"action,
                    "user_profile"userProfile,
                },
                headers: {
                    'X-Requested-With''XMLHttpRequest',
                },
                success: function(data) {
                    var res data;
                    csrfName data.csrfName;
                    csrfHash data.csrfHash;

                    if (action == "subscribe") {
                        $clicked_btn.removeClass("fa-solid fa-rss");
                        $clicked_btn.addClass("fa-solid fa-user-check");
                    } else if (action == "unsubscribe") {
                        $clicked_btn.removeClass("fa-solid fa-user-check");
                        $clicked_btn.addClass("fa-solid fa-rss");
                    }
                }
            });
        });

        $("#cancel-comment-reply-link").hide();

        $(".reply-button").on('click', function(event) {
            event.preventDefault();
            var id = $(this).attr("id");

            if ($("#li-comment-" id).find('ul').length 0) {
                $("#li-comment-" id " ul:first").prepend($("#comment-form-wrapper"));
            } else {
                $("#li-comment-" id).append($("#comment-form-wrapper"));
            }

            $("#reply-id").attr("value"id);
            $("#cancel-comment-reply-link").show();
        });

        $("#cancel-comment-reply-link").bind("click", function(event) {
            event.preventDefault();
            $("#reply-id").attr("value""");
            $("#comment-object").prepend($("#comment-form-wrapper"));
            $(this).hide();
        });

        $("#comment-form").bind("submit", function(event) {
            event.preventDefault();

            if ($("#comment-text").val() == "") {
                alert("Please enter your comment");
                return false;
            }

            $.ajax({
                type"post",
                url"<?= route_to('view_image', $image->viewkey);  ?>",
                data: $('#comment-form').serialize() + "&" + [csrfName] + "=" csrfHash,
                dataType'html',
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                },
                beforeSend: function () {
                    $('#comment-object').block({
                        message"Please wait...",
                        css: {
                            border'none',
                            padding'15px',
                            backgroundColor'#ccc',
                            '-webkit-border-radius''10px',
                            '-moz-border-radius''10px',
                        },
                        overlayCSS: {
                            backgroundColor'#ffe'
                        },
                    });
                },
                success: function (comment) {
                    var replyID = $("#reply-id").val();

                    if (replyID == "") {
                        $("#comment-object ul:first").prepend(comment);

                        if (comment.toLowerCase().indexOf("error") >= 0) {
                            $("#comment-resp-err").attr("value"comment);
                        }
                    } else {

                        if ($("#li-comment-" replyID).find('ul').length 0) {
                            $("#li-comment-" replyID).append('<ul class="comment-text">' comment '</ul>');
                        }
                    }
                    $("#comment-text").attr("value""");
                    $("#reply-id").attr("value""");
                    $("#cancel-comment-reply-link").hide();
                    $("#comment-object").prepend($("#comment-form-wrapper"));
                    $("#comment-object").unblock();
                }
            });
        });
    });
</
script

I have defined a route for both get (for the view itself) and post (for the Ajax request).
PHP Code:
// Images Routes
$routes->group('images', ['filter' => 'auth'], function ($routes) {
    $routes->get('gallery''Images\Gallery::index', ['as' => 'gallery']);
    $routes->get('view_image/(:alphanum)''Images\Gallery::view_image/$1', ['as' => 'view_image']);
    $routes->post('view_image''Images\Gallery::view_image');
}); 

So I figured out the URL:
PHP Code:
url"<?= base_url(); ?>/images/view_image/<?= $image->viewkey;?>"

However, now the updated count does not display until after page refresh.
Reply
#3

jQuery ajax post send json data
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply




Theme © iAndrew 2016 - Forum software by © MyBB