Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Build an Ajax application with the Dojo Toolkit

Joe Lennon, Product Manager, Core International
Photo of Joe Lennon
Joe Lennon is a 25-year-old mobile and web application developer from Cork, Ireland. Joe works for Core International, where he leads the development of Core's mobile HR self service solutions. Joe is also a keen technical writer, having written many articles and tutorials for IBM developerWorks on topics such as DB2 pureXML, Flex, JavaScript, Adobe AIR, .NET, PHP, Python and much more. Joe's first book, Beginning CouchDB was published in late 2009 by Apress. In his spare time, Joe enjoys travelling, reading and video games.

Summary:  The Dojo toolkit is a JavaScript library that makes the process of building large JavaScript-based Rich Internet Applications (RIAs) much simpler. With a wide range of features—from DOM querying and manipulation, Asynchronous JavaScript and XML (Ajax) request handling, excellent object-orientation support, and a full user interface widget library (Dijit)—Dojo is an excellent library to use to build a dynamic and interactive web application. In this tutorial, learn about many of the concepts of Dojo and the Dijit widget library through the development of a fully featured sample application, a contact manager system. This application lets a user browse, create, edit, and remove contacts (and contact groups) from a MySQL database. PHP is used on the server side to communicate with the database, with Dojo and the Dijit component library providing a rich, Ajax-powered user interface. The final result is a powerful web application that you can use as a foundation for your own RIAs.

Date:  01 Mar 2011
Level:  Intermediate PDF:  A4 and Letter (334 KB | 44 pages)Get Adobe® Reader®

Activity:  84355 views
Comments:  

Connecting menu options to dialog windows

Up until this point, none of the menu options in the application actually do anything. Similarly, there are a series of dialog windows that never appear. In this section, you will connect the menus to open these dialog windows accordingly.

Creating functions for configuring dialog windows

First up, create the functions given in Listing 21, which will configure the dialog windows correctly for the selected operation.


Listing 21. Functions for configuring dialog windows for selected operation

function renameGroup() {
    var group = groupsTree.get("selectedItem");
    var groupId = group.id;
    var groupName = group.name;

    dojo.byId("edit_group_id").value = groupId;
    dijit.byId("edit_group_old").set("value", groupName);
    editGroupDialog.show();
}
function refreshGroupDropDown() {
    var theStore = dijit.byId("edit_contact_group").store;
    theStore.close();
    theStore.url = "data/groups.php";
    theStore.fetch();
}
function newContact() {
    var contact = contactsGrid.selection.getSelected()[0];
    refreshGroupDropDown();
    dojo.byId("edit_contact_real_id").value = "";
    dojo.byId("edit_contact_id").value = "[NEW]";
    dijit.byId("edit_contact_group").reset();
    dijit.byId("edit_contact_first_name").reset();
    dijit.byId("edit_contact_last_name").reset();
    dijit.byId("edit_contact_email_address").reset();
    dijit.byId("edit_contact_home_phone").reset();
    dijit.byId("edit_contact_work_phone").reset();
    dijit.byId("edit_contact_twitter").reset();
    dijit.byId("edit_contact_facebook").reset();
    dijit.byId("edit_contact_linkedin").reset();
    
    dijit.byId("editContactDialog").set("title", "New Contact");
    dijit.byId("editContactDialog").show();
}
function editContact() {
    refreshGroupDropDown();
    var contact = contactsGrid.selection.getSelected()[0];
    dojo.byId("edit_contact_real_id").value = contact.id;
    dojo.byId("edit_contact_id").value = contact.id;
    dijit.byId("edit_contact_group").set("value", contact.group_id);
    dojo.byId("edit_contact_first_name").value = contact.first_name;
    dojo.byId("edit_contact_last_name").value = contact.last_name;
    dojo.byId("edit_contact_email_address").value = contact.email_address;
    dojo.byId("edit_contact_home_phone").value = contact.home_phone;
    dojo.byId("edit_contact_work_phone").value = contact.work_phone;
    dojo.byId("edit_contact_twitter").value = contact.twitter;
    dojo.byId("edit_contact_facebook").value = contact.facebook;
    dojo.byId("edit_contact_linkedin").value = contact.linkedin;
    
    dijit.byId("editContactDialog").set("title", "Edit Contact");
    dijit.byId("editContactDialog").show();
}
function moveContact() {
    var contact = contactsGrid.selection.getSelected()[0];
    var contactName = contact.first_name+" "+contact.last_name;
    var groupName = contact.name;
    
    dojo.byId("move_contact_id").value = contact.id;
    dojo.byId("move_contact_name").value = contactName;
    dojo.byId("move_contact_old").value = groupName;
    
    dijit.byId("moveContactDialog").show();
}

Next, you need to connect these functions to the relevant menu options using dojo.connect (see Listing 22).


Listing 22. Connecting menu options to functions

dojo.connect(mnuNewGroup, "onClick", null, function(e) {
    newGroupDialog.show();
});
dojo.connect(mnuRenameGroup, "onClick", null, renameGroup);
dojo.connect(ctxMnuRenameGroup, "onClick", null, renameGroup);
dojo.connect(mnuNewContact, "onClick", null, newContact);
dojo.connect(mnuEditContact, "onClick", null, editContact);
dojo.connect(ctxMnuEditContact, "onClick", null, editContact);
dojo.connect(mnuMoveContact, "onClick", null, moveContact);
dojo.connect(ctxMnuMoveContact, "onClick", null, moveContact);

In Listing 22, the New Group menu option is connected to an anonymous function, as it only has a single line to open the New Group dialog, so it doesn't really warrant a function of its own. Of course, if you prefer, you could put all of the functions used here in anonymous blocks like this, but I've separated them out, as it's easier to explain this way.

You can now reload the application and load any menu (except for the Delete options) and see the relevant dialog window open and load as appropriate. You'll probably notice right away that none of the buttons in these dialogs (except the hide "X" icon in the top right) actually do anything yet. You'll implement those features shortly. Figure 8 shows an example of the Move Contact window in action.


Figure 8. Move Contact dialog window working
Move Contact window with the     contact's name, current group, and a field to enter the group you want to move the     contact to.

Deleting groups and contacts

In the previous section, you learned how to connect all menus to their relevant dialogs, except for the delete actions. That is because the delete actions do not have a dialog window. Instead, the application should prompt the user to confirm that they want to delete a group or contact, and if they click the appropriate button, it should proceed with the deletion.

Dojo's shortcomings are few and far between, but, unfortunately, one of them is an out-of-the-box confirmation dialog box. Luckily, it's quite simple to build a custom dialog that does just that. To create a confirmation dialog box, add the function shown in Listing 23 to the script.js file.


Listing 23. Function to create a confirmation dialog box

function confirmDialog(title, body, callbackFn) {
    var theDialog = new dijit.Dialog({
        id: 'confirmDialog',
        title: title,
        draggable: false,
        onHide: function() {
            theDialog.destroyRecursive();
        }
    });

    var callback = function(mouseEvent) {
        theDialog.hide();
        theDialog.destroyRecursive(false);

        var srcEl = mouseEvent.srcElement ? mouseEvent.srcElement : mouseEvent.target;

        if(srcEl.innerHTML == "OK") callbackFn(true);
        else callbackFn(false);
    };

    var message = dojo.create("p", {
        style: {
            marginTop: "5px"
        },
        innerHTML: body
    });
    var btnsDiv = dojo.create("div", {
        style: {
            textAlign: "center"
        }
    });
    var okBtn = new dijit.form.Button({label: "OK", id: "confirmDialogOKButton", 
onClick: callback });
    var cancelBtn = new dijit.form.Button({label: "Cancel", 
id: "confirmDialogCancelButton", onClick: callback });

    theDialog.containerNode.appendChild(message);
    theDialog.containerNode.appendChild(btnsDiv);
    btnsDiv.appendChild(okBtn.domNode);
    btnsDiv.appendChild(cancelBtn.domNode);

    theDialog.show();
}

This function accepts three arguments: the title to display in the dialog, the message to show, and the function that should be called back after the user clicks OK or Cancel. This function is called with a true value if OK is pressed and a false value if Cancel is pressed.

You can now use this function to create confirmation dialogs for the Delete Group and Delete Contact menu options. The results of deleting (and other CRUD operations you'll see in the next section) cause the okDialog box to be shown. So, let's get a handle to the message in that box now, while also getting the OK button to hide the dialog (see Listing 24).


Listing 24. Use the OK button to hide the dialog

var okDialogMsg = dojo.byId("okDialogMessage");
dojo.connect(okDialogOK, "onClick", null, function(e) {
dijit.byId("okDialog").hide();
});    

Listing 25 contains the code for the function that handles deleting groups.


Listing 25. deleteGroup function

function deleteGroup() {
    confirmDialog("Confirm delete", "Are you sure you wish to delete this group? 
This will also delete any contacts in this group.<br />This action cannot 
be undone.", function(btn) {
        if(btn) {
            var group = groupsTree.get("selectedItem");
            var groupId = group.id;
            var groupName = group.name;

            dojo.xhrPost({
                url: "data/delete_group.php",
                handleAs: "json",
                content: {
                    "group_id": groupId
                },
                load: function(data) {
                    if(data.success) {
                        groupsStore.fetch({
                            query: {"id": groupId.toString()},
                            onComplete: function (items, request) {
                                if(items) {
                                    var len=items.length;
                                    for(var i=0;i<len;i++) {
                                        var item = items[i];
                                        groupsStore.deleteItem(item);
                                    }
                                }
                            },
                            queryOptions: { deep: true}
                        });
                        groupsStore.save();

                        groupsTree.set("selectedItem", groupsModel.root);
                        updateDataGrid(groupsModel.root);
                        okDialog.set("title","Group deleted successfully");
                        okDialogMsg.innerHTML = "The group <strong>"+groupName+"
</strong> was deleted successfully.";
                        okDialog.show();
                    }
                    else {
                        okDialog.set("title","Error deleting group");
                        okDialogMsg.innerHTML = data.error;
                        okDialog.show();
                    }
                },
                error: function(data) {
                    okDialog.set("title","Error deleting group");
                    okDialogMsg.innerHTML = data;
                    okDialog.show();
                }
            });
        }
    });
}

There's a bit of new ground to cover here, but the deleteContact function is very similar, so let's add that now too, and I'll discuss both in tandem.


Listing 26. deleteContact function

function deleteContact() {
    var confirmed = false;
    confirmDialog("Confirm delete", "Are you sure you wish to delete this 
contact?<br />This action cannot be undone.", function(btn) {
        if(btn) {
            var contact = contactsGrid.selection.getSelected()[0];
            var contactId = contact.id;
            var contactName = contact.first_name+" "+contact.last_name;

            dojo.xhrPost({
                url: "data/delete_contact.php",
                handleAs: "json",
                content: {
                    "contact_id": contactId
                },
                load: function(data) {
                    if(data.success) {
                        var treeSel = groupsTree.get("selectedItem");
                        var groupId;
                        if(treeSel) {
                            groupId = treeSel.id;
                        } else {
                            groupId = 0;
                        }
                        var url = contactsStore.url+"?group_id="+groupId;
                        var newStore = new dojo.data.ItemFileReadStore({url:url});
                        contactsGrid.setStore(newStore);
                        refreshGrid();

                        okDialog.set("title","Contact deleted successfully");
                        okDialogMsg.innerHTML = "The contact <strong>"
+contactName+"</strong> was deleted successfully.";
                        okDialog.show();
                    }
                    else {
                        okDialog.set("title","Error deleting contact");
                        okDialogMsg.innerHTML = data.error;
                        okDialog.show();
                    }
                },
                error: function(data) {
                    okDialog.set("title","Error deleting contact");
                    okDialogMsg.innerHTML = data;
                    okDialog.show();
                }
            });
        }
    });
}

Both of these functions use the new confirmation dialog function to ask the user to confirm the deletion. Deleting a group will cascade delete any contacts in that group, so the user is warned about that in the case of attempting to delete a group. If the user confirms, the functions go to either the group's tree or contacts grid as required and gets the detail of the item that needs to be deleted. An Ajax dojo.xhrPost function call is then used to asynchronously call the relevant server-side PHP API. The JSON response received from this is then parsed and used to display a relevant success or error message.

Finally, you need to connect these functions to the relevant events (that is, the menu options). The code in Listing 27 does just that.


Listing 27. Connecting menu options to delete functions

dojo.connect(mnuDeleteContact, "onClick", null, deleteContact);
dojo.connect(ctxMnuDeleteContact, "onClick", null, deleteContact);
dojo.connect(mnuDeleteGroup, "onClick", null, deleteGroup);
dojo.connect(ctxMnuDeleteGroup, "onClick", null, deleteGroup);

You can now save and reload your application. If you try to delete a contact, you should see the message shown in Figure 9.


Figure 9. Delete confirmation dialog box
A message box asking you to confirm     the deletion.

Pressing OK will actually go ahead and delete the contact, and the following message will subsequently be displayed (see Figure 10).


Figure 10. Deletion successful message
A message box telling you the     contact was successfully deleted.

You'll also notice that the relevant contact has been removed from the underlying grid. If you delete a group, you should see similar functionality (except that deleting a group also deletes all the contacts in that group).

6 of 11 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=629347
TutorialTitle=Build an Ajax application with the Dojo Toolkit
publish-date=03012011
author1-email=joe@joelennon.com
author1-email-cc=bwetmore@us.ibm.com