• No results found

Adding Inline Category Suggestions

In document Tango With Django 19 (Page 188-193)

18. AJAX in Django with JQuery

18.3 Adding Inline Category Suggestions

It would be really neat if we could provide a fast way for users to find a category, rather than browsing through a long list. To do this we can create a suggestion component which lets users type in a letter or part of a word, and then the system responds by providing a list of suggested categories, that the user can then select from. As the user types a series of requests will be made to the server to fetch the suggested categories relevant to what the user has entered.

Workflow

To do this you will need to do the following.

• Create a parameterised function calledget_category_list(max_results=0, starts_with='')

that returns all the categories starting withstarts_withifmax_results=0otherwise it returns

up tomax_resultscategories.

– The function returns a list of category objects annotated with the encoded category denoted by the attribute,url

• Create a view called suggest_category which will examine the request and pick out the category query string.

– Assume that a GET request is made and attempt to get the query attribute.

– If the query string is not empty, ask the Category model to get the top 8 categories that start with the query string.

– The list of category objects will then be combined into a piece of HTML via template. – Instead of creating a template calledsuggestions.htmlre-use thecats.htmlas it will

be displaying data of the same type (i.e. categories).

– To let the client ask for this data, you will need to create a URL mapping; lets call it category_suggest

With the mapping, view, and template for this view in place, you will need to update thebase.html

template and add in some javascript so that the categories can be displayed as the user types. In thebase.htmltemplate modify the sidebar block so that a div with an id=”cats” encapsulates the

categories being presented. The JQuery/AJAX will update this element.

• Above this<div> add an input box for a user to enter the letters of a category, i.e.:<input

class="input-medium search-query" type="text" name="suggestion" value="" id="suggestion" />

With these elements added into the templates, you can add in some JQuery to update the categories list as the user types.

1 - Associate an on keypress event handler to the *input* with `id="suggestion"` 2 - `$('#suggestion').keyup(function(){ ... })`

3 - On keyup, issue an ajax call to retrieve the updated categories list 4 - Then use the JQuery `.get()` function i.e. `$(this).get( ... )`

5 - If the call is successful, replace the content of the `<div>` with id="cats" w\ 6 ith the data received.

7 - Here you can use the JQuery `.html()` function i.e. `$('#cats').html( data )`

Parameterise the Get Category List Function

In this helper function we use a filter to find all the categories that start with the string supplied. The filter we use will be istartwith, this will make sure that it doesn’t matter whether we use

upper-case or lower-case letters. If it on the other hand was important to take into account whether letters was upper-case or not you would usestartswithinstead.

def get_category_list(max_results=0, starts_with=''): cat_list = []

if starts_with:

cat_list = Category.objects.filter(name__istartswith=starts_with)

if max_results > 0:

if len(cat_list) > max_results:

cat_list = cat_list[:max_results]

return cat_list

Create a Suggest Category View

Using theget_category_listfunction we can now create a view that returns the top 8 matching

def suggest_category(request): cat_list = []

starts_with = ''

if request.method == 'GET':

starts_with = request.GET['suggestion'] cat_list = get_category_list(8, starts_with)

return render(request, 'rango/category_list.html', {'cat_list': cat_list })

Note here we are re-using therango/cats.htmltemplate :-).

Map View to URL

Add the following code tourlpatternsinrango/urls.py:

url(r'^suggest_category/$', views.suggest_category, name='suggest_category'),

Update Base Template

In the base template in the sidebar div add in the following HTML code:

<ul class="nav nav-list">

<li class="nav-header">Find a Category</li> <form>

<label></label>

<li><input class="search-query span10" type="text"

name="suggestion" value="" id="suggestion" /> </li>

</form> </ul>

<div id="cats"> </div>

Here we have added in an input box withid="suggestion"and div withid="cats"in which we

will display the response. We don’t need to add a button as we will be adding an event handler on keyup to the input box which will send the suggestion request.

Add AJAX to Request Suggestions

$('#suggestion').keyup(function(){

var query;

query = $(this).val();

$.get('/rango/suggest_category/', {suggestion: query}, function(data){ $('#cats').html(data);

}); });

Here, we attached an event handler to the HTML input element withid="suggestion"to trigger

when a keyup event occurs. When it does the contents of the input box is obtained and placed into thequeryvariable. Then a AJAX GET request is made calling/rango/category_suggest/with the queryas the parameter. On success, the HTML element with id=”cats” i.e. the div, is updated with

the category list html.

Exercises

To let registered users quickly and easily add a Page to the Category put an “Add” button next to each search result. - Update thecategory.htmltemplate: - Add a mini-button next to each search result (if the user is authenticated), garnish the button with the title and URL data, so that the JQuery can pick it out. - Put a <div> withid="page"around the pages in the category so that it can be updated when pages are added. - Remove that link toaddbutton, if you like. - Create a view auto_add_page that accepts a parameterised GET request (title, url, catid) and adds it to the category - Map an url to the viewurl(r'ˆauto_add_page/$', views.auto_add_page, name='auto_add_page'),- Add an event handler to the button using JQuery - when added hide the button. The response could also update the pages listed on the category page, too.

Hints

HTML Template code: {lang=”html”,linenos=off} {% if user.is_authenticated %} <but- ton data-catid=”{{category.id}}” data-title=”{{ result.title }}” data-url=”{{ result.link }}” class=”rango-add btn btn-mini btn-info” type=”button”>Add</button> {% endif %} JQuery code:

Note here we are assigned the event handler to all the buttons with classrango-add. View code:

@login_required

def auto_add_page(request): cat_id = None

url = None title = None context_dict = {}

if request.method == 'GET':

cat_id = request.GET['category_id'] url = request.GET['url']

title = request.GET['title']

if cat_id:

category = Category.objects.get(id=int(cat_id))

p = Page.objects.get_or_create(category=category, title=title, url=url) pages = Page.objects.filter(category=category).order_by('-views') # Adds our results list to the template context under name pages. context_dict['pages'] = pages

In document Tango With Django 19 (Page 188-193)