Login

My Profile - Populating Forms from the Database

In the prior post we showed you how to build a parent form which performs an asynchronous (AJAX) call to dynamically repaint a child form.

In this post we'll detail the child form.

First we need to create a path (url) which maps to our form. Drupal calls it's request dispatching mechanism "Menu Callbacks". We implemented hook_menu() already, we'll add a new callback definition:

     $items['my_profile/admin/add_alias/js/%'] = array(
        'load arguments'=>array(5),
        'page callback' => 'my_ajax_get_form',
        'page arguments'=>array('admin_add_alias_form',4),
        'access arguments' => array('access content'),
        'type' => MENU_CALLBACK,
    );

So we just created a URL http://MYSITE/myprofile/admin/add_alias/js/. Our parent form will make an ajax call to this url to repaint the following form. The "%" allows to use a wildcard, we'll pass the user's numeric identifier. We use the numeric identifier to look up the correct record in the database.

function admin_add_alias_form(&$form_state,$uid) {
 
    $name = '';
 
    if (count($form_state['post']) == 0) {
        $dbResult = db_query(
            'select name from {users} where uid = %d',$uid);
        if ($dbResult) {
            $name = db_result($dbResult);
        }
    } else {
        $name = $form_state['post']['name'];
     }
 
    $weight = 0;
    $form['#redirect'] = 'my_profile/maintenance';
 
    $title = 'Alias settings for '.$name;
 
    $form['contact'] = array(
        '#type' => 'fieldset',
        '#title' => t($title),
        '#weight' => 5,
        '#collapsible' => FALSE,
        '#collapsed' => FALSE,
    );
 
    $form['contact']['alias'] = array(
        '#type'=>'textfield',
        '#title'=>t('Alias'),
        '#default_value'=>'',
        '#maxlength'=>80,
        '#size'=>60,
        '#weight'=>$weight++);
 
     $form['contact']['cancel']= array(
        '#prefix'=>'<table><tr><td>',
        '#suffix'=>'</td>',
        '#type'=>'submit',      
        '#value'=> t('Cancel'),
        '#weight'=>$weight);
 
    $form['contact']['submit']= array(
        '#prefix'=>'<td>',
        '#suffix'=>'</td></tr></table>',
        '#type'=>'submit',
        '#value'=> t('Add Alias'),
        '#weight'=>$weight);
 
    $form['name'] = array(
        '#type'=>'hidden',
        '#value'=>$name
    );
 
     $form['uid'] = array(
        '#type'=>'hidden',
        '#value'=>$uid
    );
 
    return $form;
}
 
 
function admin_add_alias_form_validate($form, &$form_state) {
    if ($form_state['values']['op'] == 'Cancel') {
        return;
    }
 
    if (empty($form_state['values']['alias'])) {
       form_set_error('alias',
          "Alias Must Have A Value"
       );
    }
 }
 
function admin_add_alias_form_submit($form, &$form_state) {
    switch($form_state['values']['op']) {
        case 'Cancel' :
            drupal_set_message('Operation Cancelled');
            drupal_goto('my_profile/maintenance');
        break;
        case 'Add Alias' :
            $dbResult =  addAlias(
                 $form_state['values']['alias'],
                   $form_state['values']['uid']);
            if ($dbResult) {
                drupal_set_message(
                   $form_state['values']['alias'].
                      '  Added Successfully');
            } else {
                drupal_set_message(
                        'Unexpected Exception: Unable to add ' .
                        $form_state['values']['alias']);
            }
        break;
    }
}

Explanation:

In this example we removed the "required" attribute from the "alias" text field. That way we corrected the logic flaw I talked about earlier. We also added a custom validation handler.

If an administrator blanks out the current alias and then clicks on cancel we ignore the blank field. However, if the administrator clicked on submit with a blank field, our validation handler throws an error.

The form function is fairly simple. Drupal forms by default set the form's action attribute to the same page. Therefore, the path that we mapped will get called twice when either the submit or cancel button is clicked.

We don't want to do a database lookup twice if we don't have to. What we do instead is:

  • First time form function is called we go to the database and do our lookup.
  • The "post" array tells us whether the form is being called for the first time or not.
  • After we do our database look up, we store the "name" value in a "hidden" field. That way we can use the user's name for as a success of failure message.

The submit handler simply uses our dao objecto to save the update (and/or delete) the database.