Your users don't like to wait. So it's best to load all or portions of a page with Javascript without having to do a traditional click-wait-entire page reload.
AJAX stands for Asynchronous Javascript And XML. It's not a separate language, but uses JS to create an XMLHttpRequest that calls the site's backend. This function can make changes in the database as a POST, or it could GET data that the JS would then use to update the page without having to refresh. Below are examples of each, and they require:
One of our current projects is a survey app that stores the user's answers as they fill out the survey. After they click on an answer, the data is immediately saved in the database.
JS (using jQuery):
// note: this line only works in the template
save_answer_link = "{% url 'survey:save_answer' %}";
$("#survey-page input[type='radio']").click(function(){
save_answer($(this).parents(".question"));
});
function save_answer(question) {
$.post(save_answer_link, {
'csrfmiddlewaretoken': $("input[name='csrfmiddlewaretoken']").val(),
'question_pk': $(question).find("input[name^='question-']").val(),
'answer': $(question).find(".answer-result").val(),
'na': $(question).find(".notapplicable").is(":checked") ? 1 : 0
});
};
Notice the POST url is save_answer
, set in urls.py:
url(
regex=r'^save_answer',
view=views.save_answer,
name='save_answer'
),
In the view class, take the data passed from the Javascript, and save it as a UserAnswer object (a custom model):
def save_answer(request):
question_pk = request.POST.get('question_pk')
question = Question.objects.get(pk=question_pk)
answer = request.POST.get('answer') or None
not_applicable = int(request.POST.get('na'))
else:
try:
ans = get_object_or_404(
UserAnswer, question=question, user=request.user)
except:
ans = UserAnswer(user=request.user, question=question)
ans.not_applicable = not_applicable
ans.answer = None if not_applicable else answer
ans.save()
# Return a response. An empty dictionary is still a 200
return HttpResponse(json.dumps([{}]), content_type='application/json')
Another of our projects features a form with a series of dropdowns for a student to choose a major. The options available in each dropdown depend on the previous answers, based on what majors are available at the selected campus and department. No data needs to be saved in the database yet, but we need to access the database to get the values for each dropdown.
The example below is for when the user selects a department. The list of majors then updates to only show the majors available within that department and campus.
JS (jQuery):
// note: this line only works in the template
majors_link= "{% url 'majors_per_campus' %}";
$('#program-listing').on("change", 'select[name=department]', function(){
pgm = '#' + $(this).parents(".program-info").attr("id");
url = majors_link + '?campus='+ $(pgm + ' select[name=campus]').val() + '&department='+ $(this).val();
// 'data' is what is returned from the view class
$.getJSON(url, function(data) {
options = ""
$.each(data, function () {
options += "<option value='" + this.id + "'>" + this.value + "</option>";
});
blank_option = "<option value=''>--Select--</option>"
$(pgm + ' select[name=major]').find('option').remove().end().append($(blank_option + options));
})
});
urls.py:
url(
r'^majors_per_campus',
view.get_majors_for_campus,
name='majors_per_campus'
),
Python view class:
def get_majors_for_campus(request):
"""Check the department to get a set of all majors
available in the selected department
"""
campus = request.GET.get('campus')
department = request.GET.get('department')
if not (campus and department):
return HttpResponse(json.dumps([{}]), content_type='application/json')
majors = Major.objects.filter(campus=campus, department=department)
major_choices = [dict(id=m.pk, value=m.title) for m in majors]
return HttpResponse(
json.dumps(major_choices),
content_type='application/json',
)