1

I am trying to code one of my first Drupal modules and hitting this problem.

I have a simple form in a custom module, that checks value of field_status and depending on if it is "down" or "up" executes one of two bash scripts "startup" or "shutdown" respectively. Here is the code:

function status_form_submit($form, &$form_state) {
   $node = menu_get_object();
   $status_code = $node->field_status_code[LANGUAGE_NONE][0]['value'];
if ($status_code=="down") {
   $string = shell_exec('ssh startup);
   $node->field_status_code[LANGUAGE_NONE][0]['value'] = "up";
   node_save($node);
} else {
   $string = shell_exec('ssh shutdown);
   $node->field_status_code[LANGUAGE_NONE][0]['value'] = "down";
   node_save($node);
}

drupal_set_message($string);
return $form;
}

The submission button:

function status_form($form, &$form_state) {
$form['status'] = array('#markup' => block_content());
    $node = menu_get_object();
    $status = $node->field_status[LANGUAGE_NONE][0]['value'];
    if ($status=="down") {
    $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Start up'),
    );
    } else {
    $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Shut down'),
  );

}

The bash scripts have to take from 3 to 5 minutes, during which I'd like to entertain a user, but don't know how to "release" the browser window to do something else - ideally to start showing some improvised status bar because I know in PHP it is not possible to know the status of the process until it is really finished and sent back to user browser.

I tried to add '#ajax' => array( 'callback' => 'status_form_submit'), like so:

 $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Shut down'),
    '#ajax' => array( 'callback' => 'status_form_submit'),

however unfortunately it failed to execute the form.

Could anyone help me to properly apply ajax or jquery or direct me to another way of to get this done? Thanks for attention!

Edit:

With the modification suggested by 2pha, my Ajax button starts working but giving this error in a popup window:

An AJAX HTTP error occurred.
HTTP Result Code: 500
Debugging information follows.
Path: /system/ajax
StatusText: Service unavailable (with message)
ResponseText: #0  entity_extract_ids(node, stdClass Object ([field_status_code] => Array ([und] => Array ([0] => Array ([value] => down))))) called at [/home/dev/public_html/modules/field/field.attach.inc:191]
#1  _field_invoke(presave, node, stdClass Object ([field_status_code] => Array ([und] => Array ([0] => Array ([value] => down))))) called at [/home/dev/public_html/modules/field/field.attach.inc:914]
#2  field_attach_presave(node, stdClass Object ([field_status_code] => Array ([und] => Array ([0] => Array ([value] => down))))) called at [/home/dev/public_html/modules/node/node.module:1085]
#3  node_save(stdClass Object ([field_status_code] => Array ([und] => Array ([0] => Array ([value] => down))))) called at [/home/dev/public_html/sites/all/modules/custom/server/server.module:171]
#4  status_form_submit(Array ([status] => Array ([#markup] => Your server is currentlyRunning,[#tree] => ,[#parents] => Array ([0] => status),[#array_parents] => Array ([0] => status),[#weight] => 0,[#processed] => ,[#required] => ,[#attributes] => Array (),[#title_display] => before,[#id] => edit-status,[#sorted] => 1,[#validated] => 1),[submit] => Array ([#type] => submit,[#value] => Shut down,[#default_value] => 1,[#ajax] => Array ([callback] => status_form_submit,[wrapper] => block-server-server-status,[event] => mousedown,[keypress] => 1,…

Edit2

After little bit modification my code looks like below, but it is till giving the same error above:

function status_form($form, &$form_state) {
$form['status'] = array('#markup' => block_content());

   $node = menu_get_object();

    $form['nid'] = array(
    '#type' => 'hidden',
    '#default_value' => $node->nid,
    );

   $status_code = $node->field_status_code[LANGUAGE_NONE][0]['value'];
   if ($status_code=="down") { $value="Start up"; } else { $value="Shut down"; }

 $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $value,

     '#ajax' => array(
     'callback' => 'status_form_submit',
     'wrapper' => 'block-server-server-status',
     ),

    );

$form['uptime'] = array('#markup' => block_uptime());
  return $form;
}

Edit3

<div id="block-server-server-status" class="block block-server">

    <h2>Server Status</h2>

  <div class="content">
    <form action="/server/141044310074320-1-1-22091820210112" method="post" id="status-form" accept-charset="UTF-8"><div><p>Your server is currently</p><p class="status virt">Running</p><input type="hidden" name="nid" value="1">
<input type="submit" id="edit-submit" name="op" value="Shut down" class="form-submit ajax-processed"><p>3 days, 19 hours, 44:05 minutes (330245 seconds) uptime</p><input type="hidden" name="form_build_id" value="form-29nkoOYINz8YhIWyfp9mALYxMKUZVKbkks6s6J3wGQM">
<input type="hidden" name="form_token" value="Fz1c4yAkg0YwhMxzhs3X3a3aBwuEoE3t0JM1uhT3yd4">
<input type="hidden" name="form_id" value="status_form">
</div></form>  </div>
</div>

1 Answer 1

1

Basically, you need to set the 'wrapper' for your returned element.
This is what it says under the '#ajax['wrapper']' part of the form api.
"This property is required for using AJAX requests in on a form element."

eg.

 $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Shut down'),
    '#ajax' => array(
      'callback' => 'status_form_submit',
      'wrapper' => 'status-form-wrapper',
    ),

Which corresponds to the div wrapped around your form so javascript knows what dom element to replace with what is returned by your submit function.
So, if using the code above, you need to wrap your form with the id 'status-form-wrapper'.

function status_form($form, &$form_state) {
  $form['prefix'] = '<div id="status-form-wrapper">';
  $form['suffix'] = '</div>';
  $form['status'] = array('#markup' => block_content());
    $node = menu_get_object();
    $status = $node->field_status[LANGUAGE_NONE][0]['value'];
    if ($status=="down") {
      $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Start up'),
    );
    } else {
      $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Shut down'),
  );
}

NOTE: I am unsure if you can set 'prefix' and 'suffix' to the form element itself, if not, you will have to nest your form elements under the wrapper div.

EDIT adding example of node id in hidden field.

function status_form($form, &$form_state) {
  $form['status'] = array('#markup' => block_content());
  $node = menu_get_object();
  // ADDING THE HIDDEN FIELD HERE
  $form['nid'] = array(
    '#type' => 'hidden',
    '#default_value' => $node->nid,
  );
  $status = $node->field_status[LANGUAGE_NONE][0]['value'];

  if ($status=="down") {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Start up'),
    );
  } else {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Shut down'),
    );
  }
  return $form;
}
18
  • thanks for your help. Unfortunately lines: $form['prefix'] = '<div id="status-form-wrapper">'; $form['suffix'] = '</div>'; give WSOD. Without them: An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging information follows. Path: /system/ajax StatusText: Service unavailable (with message) ResponseText: EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7729 of /home/dev/public_html/includes/common.inc).
    – Sasha
    Commented Sep 15, 2014 at 4:41
  • The form had already been nested in div with id "block-server-server-status". Replacing 'wrapper' => 'status-form-wrapper' in your suggested code with 'wrapper' => 'block-server-server-status', is giving: An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging information follows. Path: /system/ajax StatusText: Service unavailable (with message) ResponseText: EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7729 of /home/dev/public_html/includes/common.inc).
    – Sasha
    Commented Sep 15, 2014 at 4:47
  • Then I suspect your problem is with your call to menu_get_object as the current path in the ajax request is system/ajax so `menu_get_item' will not work in an ajax call. You are probably going to have to send an argument in the url that will allow you to load the appropriate node.
    – 2pha
    Commented Sep 15, 2014 at 8:11
  • Could you please give some specific examples of how "to send an argument in the url that will allow you to load the appropriate node" as I am unfortunately not that much experienced? Thanks!
    – Sasha
    Commented Sep 15, 2014 at 8:32
  • It would depend on where your form is being displayed. Is the form being displayed on a node page? If so, you could add a hidden form element containing the node id, then it should be available in the submit function.
    – 2pha
    Commented Sep 15, 2014 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.