.. _simple_ajax: Example Application: Simple AJAX ================================ This guide will walk you through building a simple Pecan web application that uses AJAX to fetch JSON data from a server. Project Setup ------------- First, you'll need to install Pecan: :: $ pip install pecan Use Pecan's basic template support to start a new project: :: $ pecan create myajax $ cd myajax Install the new project in development mode: :: $ python setup.py develop Adding JavaScript AJAX Support ------------------------------ For this project we will need to add `jQuery `_ support. To add jQuery go into the ``templates`` folder and edit the ``layout.html`` file. Adding jQuery support is easy, we actually only need one line of code: .. code-block:: html The JavaScript to make the AJAX call is a little more in depth but shouldn't be unfamiliar if you've ever worked with jQuery before. The ``layout.html`` file will look like this: .. code-block:: html ${self.title()} ${self.style()} ${self.javascript()} ${self.body()} <%def name="title()"> Default Title <%def name="style()"> <%def name="javascript()"> **What did we just do?** #. In the ``head`` section we added jQuery support via the `Google CDN `_ #. Added JavaScript to make an AJAX call to the server via an HTTP ``GET`` passing in the ``id`` of the project to fetch more information on #. Once the ``onSuccess`` event is triggered by the returning data we take that and display it on the web page below the controls Adding Additional HTML ---------------------- Let's edit the ``index.html`` file next. We will add HTML to support the AJAX interaction between the web page and Pecan. Modify ``index.html`` to look like this: .. code-block:: html <%inherit file="layout.html" /> <%def name="title()"> Welcome to Pecan!

Select a project to get details:

**What did we just do?** #. Added a dropdown control and submit button for the user to interact with. Users can pick an open source project and get more details on it Building the Model with JSON Support ------------------------------------ The HTML and JavaScript work is now taken care of. At this point we can add a model to our project inside of the ``model`` folder. Create a file in there called ``projects.py`` and add the following to it: .. code-block:: python class Project(object): def __init__(self, name, licensing, repository, documentation): self.name = name self.licensing = licensing self.repository = repository self.documentation = documentation def __json__(self): return dict( name=self.name, licensing=self.licensing, repository=self.repository, documentation=self.documentation ) **What did we just do?** #. Created a model called ``Project`` that can hold project specific data #. Added a ``__json__`` method so an instance of the ``Project class`` can be easily represented as JSON. The controller we will soon build will make use of that JSON capability .. note:: There are other ways to return JSON with Pecan, check out :ref:`jsonify` for more information. Working with the Controllers ---------------------------- We don't need to do anything major to the ``root.py`` file in the ``controllers`` folder except to add support for a new controller we will call ``ProjectsController``. Modify the ``root.py`` like this: .. code-block:: python from pecan import expose from myajax.controllers.projects import ProjectsController class RootController(object): projects = ProjectsController() @expose(generic=True, template='index.html') def index(self): return dict() **What did we just do?** #. Removed some of the initial boilerplate code since we won't be using it #. Add support for the upcoming ``ProjectsController`` The final piece is to add a file called ``projects.py`` to the ``controllers`` folder. This new file will host the ``ProjectsController`` which will listen for incoming AJAX ``GET`` calls (in our case) and return the appropriate JSON response. Add the following code to the ``projects.py`` file: .. code-block:: python from pecan import expose, response from pecan.rest import RestController from myajax.model.projects import Project class ProjectsController(RestController): # Note: You would probably store this information in a database # This is just for simplicity and demonstration purposes def __init__(self): self.projects = [ Project(name='OpenStack', licensing='Apache 2', repository='http://github.com/openstack', documentation='http://docs.openstack.org'), Project(name='Pecan', licensing='BSD', repository='http://github.com/pecan/pecan', documentation='https://pecan.readthedocs.io'), Project(name='stevedore', licensing='Apache 2', repository='http://github.com/dreamhost/pecan', documentation='http://docs.openstack.org/developer/stevedore/') ] @expose('json', content_type='application/json') def get(self, id): response.status = 200 return self.projects[int(id)] **What did we just do?** #. Created a local class variable called ``projects`` that holds three open source projects and their details. Typically this kind of information would probably reside in a database #. Added code for the new controller that will listen on the ``projects`` endpoint and serve back JSON based on the ``id`` passed in from the web page Run the application: :: $ pecan serve config.py Open a web browser: `http://127.0.0.1:8080/ `_ There is something else we could add. What if an ``id`` is passed that is not found? A proper ``HTTP 404`` should be sent back. For this we will modify the ``ProjectsController``. Change the ``get`` function to look like this: .. code-block:: python @expose('json', content_type='application/json') def get(self, id): try: response.status = 200 return self.projects[int(id)] except (IndexError, ValueError) as ex: abort(404) To test this out we need to pass an invalid ``id`` to the ``ProjectsController``. This can be done by going into the ``index.html`` and adding an additional ``option`` tag with an ``id`` value that is outside of 0-2. .. code-block:: html

Select a project to get details:

You can see that we added ``WSME`` to the list and the value is 3. Run the application: :: $ pecan serve config.py Open a web browser: `http://127.0.0.1:8080/ `_ Select ``WSME`` from the list. You should see the error dialog box triggered.