Learn Django

New/Edit Contact - Enable AJAX

Referring to the application design, users will be able to add and edit contacts on the account detail page. These actions can be performed without a page refresh. AJAX will be used to achieve these design goals. To enable AJAX we will need to update two resources; the JavaScript app and a Django view.

Step 1: Add JavaScript Functions

There are three functions we need to add to the JavaScript app. The first one will fetch the blank contact form from the server. The second function will fetch a prepopulated contact form that can be used to edit a contact. The last function is used to save both the new and edit contact forms to the server.

Open /.../crmeasy/crmapp/static/js/app.js, locate the // Main App section, and add the following code within the function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Main App
$(document).ready(function() {
    ...

    // Contact - Use AJAX to get the Contact Add form
    $('#cd-container').delegate('#new-contact', 'click', function(e) {
        e.preventDefault();
        $.get($(this).attr('href'), function(data) {
            $('#cd-body').append(data);
            $('#new-contact').hide();
        });
    });

    // Contact - Use AJAX to get the Contact Edit form
    $('#cd-container').delegate('.edit-contact', 'click', function(e) {
        e.preventDefault();
        var that = $(this);
        $.get($(this).attr('href'), function(data) {
            $('#new-contact').hide();
            that.parent().parent().remove();
            $('#cd-body').append(data);
        })
    });

    // Contact - Use AJAX to save the Contact Add Form
    $('#cd-container').delegate('#contact-form', 'submit', function(e) {
        e.preventDefault();
        var form = $('#contact-form');
        var url = form.attr('action');
        $.post(url, form.serialize(), function(data) {
            if ($(data).find('.errorlist').html()) {
                // If the contact form is returned we know there are errors
                $('#new-contact').hide();
                $('#cd-body').append(data);
            } else {
                // Otherwise insert the row into the table
                $('#cd-table tr:last').after(data);
                $('#new-contact').show();
            }
        });
        $(this).remove(); // Remove the form
    });

});

Code Review

Lines 5 - 12: This is the function that will fetch the new contact form from the server and load it into the #cd-body element. This uses jQuery .delegate() to intercept the click action from the user. It then gets the href location from the element, performs a HTTP GET request on it, and inserts the returning HTML into the said element.

Lines 14 - 23: This function is used to fetch the edit contact form. This is very similar to the previous function, except that after the form is fetched, the function will remove the contact being edited (line 20).

Lines 25 - 42: This function will take the new or edit contact form and send it to Django for processing (saving). If the form has an issue, for example one of the fields has a non-approved value, Django will return an error message back. Lines 31 - 34 will detect if there was an error and will include show that error to the end user to fix. If there are no errors, the new or updated contact is then inserted into the page (liens 36 - 38).

Update the View

Now that the JavaScript app has been updated, we can modify the Django view to detect AJAX requests. If AJAX is being used, instead of returning a full HTML page, Django will return just the item level HTML required to display the contact on the account detail page.

Open /.../crmeasy/crmapp/contacts/views.py file in your IDE. Locate the contact_cru() view and update it as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@login_required()
def contact_cru(request, uuid=None, account=None):

    if uuid:
        contact = get_object_or_404(Contact, uuid=uuid)
        if contact.owner != request.user:
            return HttpResponseForbidden()
    else:
        contact = Contact(owner=request.user)

    if request.POST:
        form = ContactForm(request.POST, instance=contact)
        if form.is_valid():
            # make sure the user owns the account
            account = form.cleaned_data['account']
            if account.owner != request.user:
                return HttpResponseForbidden()
            # save the data
            contact = form.save(commit=False)
            contact.owner = request.user
            contact.save()
            # return the user to the account detail view
            if request.is_ajax():
                return render(request,
                              'contacts/contact_item_view.html',
                              {'account':account, 'contact':contact}
                )
            else:
                reverse_url = reverse(
                    'crmapp.accounts.views.account_detail',
                    args=(account.uuid,)
                )
                return HttpResponseRedirect(reverse_url)
    else:
        form = ContactForm(instance=contact)

    if request.GET.get('account', ''):
        account = Account.objects.get(id=request.GET.get('account', ''))

    variables = {
        'form': form,
        'contact': contact,
        'account': account
    }

    if request.is_ajax():
        template = 'contacts/contact_item_form.html'
    else:
        template = 'contacts/contact_cru.html'

    return render(request, template, variables)

Code Review

Lines 23-33: The request object has an is_ajax() method that detects whether or not the request was made with AJAX. This section of code kicks in if the request was made with AJAX and returns just the contact_item template instead of a whole page.

Lines 46-49: This statement again checks if this is an AJAX request. If it is the contact_item_form is returned instead of the entire contact_cru page.

Commit Changes

Execute these commands to commit your changes in Git.

1
2
3
4
5
# add files
(venv)$ git add .

# commit files
(venv)$ git commit -m "activated AJAX for contact edit/new features"

Track your progress with a free account