Login

My Profile - Dynamic Ajax Form Processing

In this post we are going to discuss the final method for administering our user alias records. That method is the add new alias method.

Let's review the business requirements briefly.

A user alias is not mandatory. However, a single user account can never have more than one alias. So we have 0:1 (zero to one) relationship between alias and user accounts.

So for our add dialog, that means we need to display only user accounts that do not have a related alias.

If you look at our dbMy_profile class definition, you will notice we have a method called getUsersWithoutAlias(). That methods provides our list.

We've decided to display the list of users without aliases in a drop-down combo box (aka select list). Once a user is assigned their new alias, that user's information must be removed from the drop-down combo box (because we can't add a second alias to an account).

Drupal's AHAH function allows forms to dynamically add fields to a form. Our requirement is a little different. We don't want to add a field we want to change the attributes of a select list. Drupal's security system will throw an error if you change the number of options in a select list and then post it back to your server. The forms don't match. The select list is really a special case. If you replaced a select list with a list of text fields, Drupal wouldn't throw an exception. So that's one possibility.

We are going to something a little simpler. Our users will see "one form", but behind the scenes the page is actually displaying 2 forms (on one page). Our first form doesn't get submitted. That form contains the select list with the dynamic number of users.

Our second form allows our administrator to enter the alias value (or cancel). The second form is the form that gets submitted. Since it's only a text field and a couple of buttons, we aren't violating any of Drupal's security measures.

What we are doing is the following:

  • The administrator selects a user from the select list.
  • We perform an asynchronous call (ajax) up to our server, telling it to render a "Add Alias" form.
  • The server sends the form customized for a specific user back to our administrator's web browser
  • Only the bottom portion of the page is repainted.
We also start our select list with a "Choose" item. An extra prompt for folks who don't recognize what a select list/drop down combo box is.

The following screen shots demonstrate how the 2 forms will look. The first screen shot show what happens when an administrator clicks on "Add a User Alias".

  • Because no user account has been selected. Only the drop down combo box (select list) is displayed.
  • Next the administrator clicks on the select list.
  • Finally after a user account is selected, the second form is rendered, and the select list no longer includes the extra "choose" item.

The administrator can toggle the select list between different user accounts. The form below is repainted without a full page refresh.

Let's look at the code:

function admin_select_user_form(&$form_state) {
 
    $dbMyProfile = new dbMy_profile();
    $list = $dbMyProfile->getUsersWithoutAlias();
    $list[0]='Choose';
    $weight = 0;
    drupal_set_title('Select User to Add Alias');
 
    $form['users'] = array(
        '#type'=>'select',
        '#default_value'=>0,
        '#options'=>$list,
        '#title'=>'User\'s Without An Alias',
        '#description'=>t('Choose A User'),
        '#weight'=>$weight++,
    );
 
    $form['container'] = array(
        '#type' => 'fieldset',
        '#weight' => $weight++,
        '#prefix'=>'<div id="add-area">',
        '#suffix'=>'</div>',
        '#collapsible' => FALSE,
        '#collapsed' => FALSE,
    );
 
    $js = "
         Drupal.behaviors.selectuseralias = function(context) {
 
            var userselect =  $('#edit-users');        
            userselect.change(function(event) {
                uid = event.target.value;
 
                if (uid > 0) {
                    $(\"#edit-users option[value='0']\").remove();
                    var loadUrl = 
                     '/proto/my_profile/admin/add_alias/js/'+uid;
                    $('#add-area').load(loadUrl);                
                } else {
                    $('#add-area').empty();
                }
           })
        }";
 
        $cache_set= "$.ajaxSetup ({
		cache: false
	});
 
	var loadUrl = 'my_profile/admin/add_alias/';
	$('#load_basic').click(function(){
		$('#add-area').load(loadUrl);
	});";
 
        drupal_add_js($js, 'inline');
 
    return $form;
}

Explanation:

For sake of brevity we added our Jquery javascript in our method (as opposed to a separate file listing). For a production release, we would move the javascript to a separate file listing.

The rest of the listing is fairly simple. In our form we create a field set with an embedded empty html div. That's where we instruct our ajax call to paint the response.

Each time the administrator chooses a different user in the top form select list, the bottom form is repainted asynchronously. We use the field set to describe which user account is currently selected.

To summarize, the above processing is your basic parent/child or hierarchical display. The select list is our master record, the bottom form represents our detail record(s). In other words, we could easily replace the bottom form with a list report.

The bottom form is processed exactly like out previous listings.