Search code examples
ajaxweb2py

Why does this Web2Py ajax call fail to return the value of a variable?


Here is the relevant snippet from my Web2Py view:

{{for candidate in rows:}}
    <div class="well col-sm-12">
        <button type="button" name="up_button" onclick="ajax('{{=URL('default', 'arrow_button_callback')}}', ['name'], 'target')" class="fa fa-caret-up arrow-up fa-4x"></button>
        <span>{{=candidate.votes}}</span>
        <button type="button" name="down_button" onclick="ajax('{{=URL('default', 'arrow_button_callback')}}', ['name'], 'target')" class="fa fa-caret-down arrow-down fa-4x"></button>
        {{=IMG(_src=URL('photos',candidate.path_to_photo), _alt="Photo of Candidate")}}
        {{=candidate.name}}
        <div id="target"></div>
   </div>
{{pass}}

And the relevant snippet from my Web2Py controller:

def arrow_button_callback():
    response.flash = str(request.post_vars.name)
    return request.post_vars.name

So why do I see the string "None" in my target div (and in my flash)?

Thank you for your help. I read chapter 11 of the Web2Py book and I'm still confused.

I really want to be able to pass candidate.id (depending on which row's button was pressed) and the button direction to controller variables. Please let me know if there's a better way to do this.

--Benjamin


Solution

  • From the web2py documentation (emphasis added):

    ajax(url, [name1, name2, ...], target)

    It asynchronously calls the url (first argument), passes the values of the field inputs with the name equal to one of the names in the list (second argument)...

    In your code, your second argument is ['name']. However, there is no input field with the name "name" anywhere, so no "name" variable gets posted to web2py (therefore, request.post_vars.name is None, which is the default value returned whenever you attempt to get a variable that does not exist in request.post_vars).

    In this case, because you are not placing any data in form input fields, you can simply ignore the second argument to ajax(). Instead, pass the relevant data via the URL itself:

       {{url = URL('default', 'arrow_button_callback',
                   vars=dict(id=candidate.id, direction='up'))}}
       <button type="button" name="up_button" onclick="ajax('{{=url}}', [], 'target')"
        class="fa fa-caret-up arrow-up fa-4x"></button>
    

    Then in the arrow_button_callback controller, you can access the candidate id via request.get_vars.id (or just request.vars.id). And you can access the arrow direction via request.vars.direction. Create a new URL for the "down" button, with direction='down'.