views:

143

answers:

2

I'm writing a simple App Engine app.

I have a simple page that allows a user to move a marker on a Google map instance. Each time the user drops the marker, I want to return the long/lat to my Python app.

function initialize() {

  ... // Init map

  var marker = new GMarker(center, {draggable: true});
  GEvent.addListener(marker, "dragend", function() {
    // I want to return the marker.x/y to my app when this function is called ..
  });

}

To my (admittedly limited) knowledge, I should be:

1). Returning a JSON structure with my required data in the listener callback above

2). In my webapp.RequestHandler Handler class, trying to retrieve the JSON structure during the post method.

I would very much like to pass this JSOn data back to the app without causing a page reload (which is what has happened when I've used various post/form.submit methods so far).

Can anyone provide me with some psuedo code or an example on how I might achieve what I'm after?

Thanks.

+7  A: 

The way to prevent a page reload is to handle this with AJAX on the web page side.

Using jquery, you might do something like this:

$("#testform").submit(function() {
    // post the form values via AJAX...
    var postdata = {lat: $("#lat").val(), long: $("#long").val()} ;
    $.post('/submit', postdata, function(data) {
        // and set the location with the result
        $("#location").html(data['location']) ;
       });
    return false ;
    });

Assuming you have a web page something like this:

<p>Enter lat and long:</p>
<form id="testform" action="#" method="post">
    <p>
    <label for="lat">Lat:</label>
    <input type="text" id="lat" /> <br />
    <label for="long">Long:</label>
    <input type="text" id="long" /> <br />

    <input type="submit" value="Get Location" />
    </p>
</form>

<p>The location is:</p><p id="location">(enter lat and long above)</p>

and then have the python code return the location in a JSON dict.

Finally, I would recommend having a graceful fallback: if the user has JavaScript disabled, do a regular post to e.g. /getlocation and reload, and then have JavaScript override this to submit to a special URL that returns json, like /getlocationajax

Ryan Ginstrom
+1  A: 

If you don't want the page to update, then you need to use a XMLHttpRequest. In this example, i'm using the client-side function Request(function_name, opt_argv) and server-side RPCHandler from this Google App Engine example. I haven't tested this, but it would look like:

Client-side Javascript

function initialize() {

  ... // Init map

  var marker = new GMarker(center, {draggable: true});
  GEvent.addListener(marker, "dragend", function(position) {
    Request('update_marker_position', [ unique_identifier, position.lat(), position.lng() ] );
  });

}

Server-side Python

# Create database model for LatLng position
class LatLng(db.Model):
    lat = db.IntegerProperty()
    lng = db.IntegerProperty()

...

class RPCMethods:
    """ Defines the methods that can be RPCed.
    NOTE: Do not allow remote callers access to private/protected "_*" methods.
    """

    def update_marker_position(self, *args):
        # args[0] - unique identifier, say GAE db key
        # args[1] - lat
        # args[2] - lng
        # Note: need to do some checking that lat and lng are valid

        # Retrieve key and update position
        position = LatLng.get(db.Key(args[0])
        if position:
            position.lat = args[1]
            position.lng = args[2]
        else:
            position = LatLng(
                lat= args[1], 
                lng= args[2]
            )
        position.put()

        payload = {
            'lat': args[1],
            'lng': args[2],
        }
        return payload

You'll need to create the db entry when you serve up the page, and store the db key client side. You could also use some other unique identifier. In this case, I assumed you stored it as a global variable 'unique_identifier'.

As well, you'll need to add a callback function to handle the returning payload (with members 'lat' and 'lng'). From the example, I believe you just add your callback function as the zeroth parameter in the opt_argv array of Request. I hope this helps.

Fraser Harris