ajaxsymfonydoctrinesymfony-3.1

Can't get POST data with AJAX


I would like to show 4 objects in a page, with a "load more" button which show 4 more object each time we click.

I try to adapt a PHP script which works(tested) to Symfony. The problem is that I can't get the POST data (a page number) in my Symfony function, even if I can see it in the chrome developer toolbar...

POST variable with key 'page' and value '1' My controller:

<?php
/**
 * Content controller.
 *
 * @Route("content")
 */
class ContentController extends Controller
{

/**
 * Lists all software.
 *
 * @Route("/software", name="content_software")
 * @Method({"POST", "GET"})
 */
public function softwareAction(Request $request)
{
    if ($request->request->get('page')){
        $page_number = filter_var($_POST["page"], FILTER_SANITIZE_NUMBER_INT,
                FILTER_FLAG_STRIP_HIGH);
        $item_per_page = 4;
        $position = (($page_number-1) * $item_per_page);
        $contents = $this->getRepo()->findBy(array(),null,$item_per_page,$position);
    }
    else
    {
        $contents = "didn't work";
    }
    return $this->render('content/index.html.twig', array(
            'contents' => $contents
    ));
}
}

index.html.twig :

{% extends 'loicCoreBundle::Default/layout.html.twig' %}

{% block body %}
{{ dump(contents) }}
<script type="text/javascript">
    var track_page = 1; //track user click as page number, right now page number is 1
    load_contents(track_page); //load content

    $("#load_more_button").click(function (e) { //user clicks on button
        track_page++; //page number increment everytime user clicks load button
        load_contents(track_page); //load content
    });

        //Ajax load function
        function load_contents(track_page){

            $.post( "{{ path('content_software') }}", {'page': track_page}, function(data){

                if(data.trim().length == 0){
                    //display text and disable load button if nothing to load
                    $("#load_more_button").text("No more records!").prop("disabled", true);
                }
            });
        }           
</script>
{% endblock %}

Solution

  • I'm not sure where your errors are coming from, I've done a similar test which just works (no problems with $request->request->get()).

    You are however loading a full template (index.html) for each sub request as well. Usually you want to separate calls like this into api like methods, however for simple things its a bit silly.

    Here is an expanded/ updated version of what I tested, I avoided post data all together and just used the method as switch. This worked fine so try and figure out where you went wrong using this as reflection (or whatever you like to do with it). Note this uses a simple PHP range array for test data, not entities but it should remain the same principle.

    Controller

        /**
         * @Route(
         *      "software/{page}/{limit}",
         *      name="content_software",
         *      requirements = {
         *          "page": "[1-9]\d*",
         *          "limit": "[1-9]\d*"
         *      }
         * )
         */
        public function softwareAction(Request $request, $page = 1, $limit = 4) {
            if ($request->isMethod('POST')) {
                // replace these two lines with database logic (SELECT & LIMIT)
                $start = ($page - 1) * $limit;
                $items = array_slice(range(1, 10), $start, $limit); // Just using a simple item array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as test data
    
                $content = '';
                foreach ($items as $item) {
                    $content .= $this->get('twig')->render('someItemTemplate.html.twig', ['item' => $item]);
                }
    
                return new Response($content);
            } else {
                // alternatively you can send out the default items here for the first get request
                // and use the same item template above with {% embed %} to render them in this template
                return $this->render('someTemplate.html.twig');
            }
        }
    

    someTemplate.html.twig

    <html>
        <head>
            <title>Cake or death?</title>
        </head>
        <body>
            <ul id="put-the-things-here"></ul>
            <button id="next_please">Ehh cake please!</button>
    
            <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
            <script>
                var pageTracker = 1,
                    $next = $("#next_please"),
                    $target = $('#put-the-things-here');
    
                load_contents(pageTracker);
    
                $next.click(function (e) {
                    load_contents(++pageTracker);
                });
    
                function load_contents(page) {
                    // using post just for the request method (page is in the url)
                    $.post("{{ path('content_software') }}/" + page,
                        function (data) {
                            if (data) {
                                $target.append(data);
                            } else {
                                $target.append('<li>We are out of cake.</li>');
                                $next.attr('disabled', true);
                            }
                        }
                    );
                }
            </script>
        </body>
    </html>
    

    someItemTemplate.twig

    <li>Cake: {{ item }}</li>