views:

280

answers:

1

I have a form that is added through the nodeapi displayed only on view mode. Users can select an item from a select menu and their choice will automatically get saved to the database with a hook_menu callback on change. If the user has javascript disabled, it'll submit normally with the form api. This is all working fine, but now for security reasons I want to submit the ajax version via the form api too. My form_name_submit is simple like:

function mymodule_test_form_submit($form, &$form_state) {
  global $user;
  db_query("INSERT INTO {mymodule} (nid, uid, status, created) VALUES (%d, %d, %d, " . time() . ")", $form['#parameters'][2], $user->uid, $form_state['values']['mymodule_status']);
}

My ajax:

$('.mysubmit').css('display', 'none');
$('.myclass').change(function() {
  $.ajax({
    type: 'POST',
    url: Drupal.settings.basePath + 'mymodule/set/' + $nid + '/' + $('.myclass').val(),
    dataType: 'json',
    data: { 'ajax' : true, 'form_build_id' : $('#mymodule-form input[name=form_build_id]').val() }
  });
});

And my callback function:

function mymodule_set($nid, $status) {
  $form_build_id = $_POST['form_build_id'];
  $form_state = array('storage' => NULL, 'submitted' => FALSE);
  $form = form_get_cache($form_build_id, $form_state);
  $args = $form['#parameters'];
  $form_id = array_shift($args);
  $form['#post'] = $_POST;
  $form['#redirect'] = FALSE;
  $form['#programmed'] = FALSE;
  $form_state['post'] = $_POST;
  drupal_process_form($form_id, $form, $form_state);
}

Originally my callback function was about the same as my submit function, but now I'm trying to use the submit function with ajax as well. Is this the right way to use drupal_process_form? The form is grabbed from the cache, it get's validated and submitted if no errors? I'm using some code from this tutorial to apply to my situation: http://drupal.org/node/331941 There doesn't seem to be any examples of what I'm trying to do. I also have $form['#cache'] = TRUE; in my form function.

How does drupal_process_form compare the submitted values with the original form to check for integrity? Am I supposed to add my values to the form_state since the form state will be empty with ajax. Been stuck on this for a few days, hopefully someone has experience with this.

Thanks.

A: 

I had to do somenthing similar to you in the past and read the same tutorial you posted, unfortunately there isn't much information avalaible about this and it was headache for me to make it work. I don't remember well the details but I was taking a look to the code I wrote and here are a couple of suggestions that may work for you:

IF you are doing this in a node form, adding the #ahah property in a form alter may not work, I remember having seen an issue about this that wasn't solved at that moment. if this is the case, use this code for attaching the ahah binding, you'll not need "efect", "method" or "progress" since you just want to submit the form, not to change anything about it:

function YOURMODULE_form_alter(&$form, $form_state, $form_id) {
  if ('YOURCONTENTTYPE_node_form' == $form_id) {
    //the only way I could make it work for exisiting fields is adding the binding "manually"
    $ahah_binding = array(
      'url'   => url('YOURCALLBACKPATH'), 
      'event' => 'change',
      'wrapper' => 'FIELD-wrapper',
      'selector' => '#FIELD',
      'effect'   => 'fade',
      'method'   => 'replace',
      'progress' => array('type' => 'throbber'),
    );

    drupal_add_js('misc/jquery.form.js');
    drupal_add_js('misc/ahah.js');
    drupal_add_js(array('ahah' => array('FIELDd' => $ahah_binding)), 'setting');

    //force the form to be cached
    $form['#cache'] = TRUE;
  }
}
  • Here is my callback function, note that it has some modifications from the tutorial you posted:

    function YOURMODULE_js() {
    
    
      // The form is generated in an include file which we need to include manually.
      include_once 'modules/node/node.pages.inc';
      // We're starting in step #3, preparing for #4.
      //I have to add the 'rebuild' element, if not an empty node was created
      $form_state = array('storage' => NULL, 'submitted' => FALSE, 'rebuild' => TRUE);
      $form_build_id = $_POST['form_build_id'];
      // Step #4.
      $form = form_get_cache($form_build_id, $form_state);
    
    
      // Preparing for #5.
      $args = $form['#parameters'];
      $form_id = array_shift($args);
      $form_state['post'] = $form['#post'] = $_POST;
      $form['#programmed'] = $form['#redirect'] = FALSE;
    
    
      // if you want to do any modification to the form values, this is the place 
    
    
      // Step #5.
      drupal_process_form($form_id, $form, $form_state);
      // Step #6 and #7 and #8.
      $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
    
    
      // Final rendering callback.
      drupal_json(array('status' => TRUE, 'data' => $output));
    }
    

As I said before there are details that I have forgot but maybe this will help you.

Good Luck.

Flupkear
Thanks for posting. The form is being added by nodeapi since I only want the form to show on node view. I haven't done any AHAH before, so would I use the same code from the form_alter you posted? I'll try playing around with it now...
Wade
If the form is a node form, then the code I posted should work with some small modifications, the only thing I'm not 100% sure is that if drupal_process_form will call the submit function automatically.
Flupkear
Hmm, I don't see any difference from before. How does drupal actually know what the values are to compare? Or do you need to add them to the form state? If you don't do that, won't the form state just be empty, but I did already try adding a values array to the form_state, but no difference.
Wade
did you tried adding the value to the form state in this way? $form_state['post']['FIELDNAME'][0]['value'] = 'value to save';that should work for a single value field, anyway you should print_r the element you are trying to modify in the form submit so you know what values is expecting and how it's formed.Anyway I didn't tried adding a new value to a form, so I'm not sure if you should add the value into $form_state or $form, you could try in both.
Flupkear
If all this fail and you want to try another approach, you could always use a drupal_execute (http://www.lullabot.com/articles/quick_and_dirty_cck_imports), but it's not a very "clean" implementation.Sorry of not being of much help, but I din't tried what you need exactly
Flupkear
Thanks for the drupal_execute suggestion. It's finally working now. :) It seems okay to me, less code so not sure why it's not clean, but for now it should do.
Wade