Ajax in Drupal via jQuery by Example

SageOfCode's picture

I am writting becasue I have been working on a module that utilizes Ajax in Drupal via jQuery called "ActiveField".
The module is somewhat unique from other examples that I have seen in that:
1. It works with CCK content types while they are being created (i.e. before they are persisted to the database)
2. It works with existing themes and does not have it's own theme

The module is documented at: http://www.sageofcode.com/?p=59

I litterally own 8 books on drupal (more books on the way) and the Lullabot DVD. I have read just about every article that I could find on Ajax/jQuery/Drupal. Based on feedback from other members of the Drupal community, the module is nearly working.
(c.f. http://drupal.org/node/301959 ). Once the module is working, I would like to submit it as a contributed module and contribute to Ajax/jQuery/Drupal online docs (e.g. http://drupal.org/node/305747 is "[TO BE COMPLETED....]"). I have a diverse back ground which includes documentation and training; I have managed and lead documentation and training teams in the past. I welcome the opportunity to apply these skills to build documenation and training materials on Ajax, jQuery and Drupal.

Below is the updated code.
I have read, re-read, and re-, re-read every line of code and character. I have also debugged every which possible that I know of. I am truely stumped. S.O.S.

Every thing is working unitl the ajax request is made to the call back function via the URL.
More specifically, whe the .js file is loaded, the following error is displayed in the Console tab of FireBug:

ActiveField.module

Firebug needs to POST to the server to get this information for url:
http://sageofcode.com/ActiveField/field-trip

This second POST can interfere with some sites. If you want to send the POST again, open a new tab in Firefox, use URL 'about:config', set boolean value 'extensions.firebug.allowDoublePost' to true
This value is reset every time you restart Firefox This problem will disappear when https://bugzilla.mozilla.org/show_bug.cgi?id=430155 is shipped.

I click the "Load Response" button and I get this error:

<html><head><title>404 Not Found</title></head>
<body bgcolor=white>
<h1>404 Not Found</h1>
The requested URL /ActiveField/field-trip does not exist.
</body></html>

When I got to the http://ActiveField/field-trip , I get

Palo Alto

What I find interesting is that when I go to the Menu callback of the "plus1" module example in chapter 17 of "Pro Drupal Devlopment" 1st Ed., I get a blank white page. The "plus1" module works just fine on my site. I have compared every character in the ActiveField_menu() function, and I cannot see an issue. I have confirmed that the code is executed. In fact, the access privilege is created!
Another interesting observation is that the menu table does not have a row for the MENU_CALLBACK for the plus1 module; at least as far as I can see.

The issue appears to be with the actual, path. But, I am out of ideas on how to debug this.

<?php
//$id$

/
* @file
* A dynamic parent-to-child field module via Drupal, Ajax, and jQuery

/

/


Implementation of hook_perm().
* Adding the "Use ActiveField" permission to Drupal's role-based access control page.
* Prevents Anonymous use.

/
function ActiveField_perm(){
    return array('Use ActiveField');
}

/
* Implementation of hook_menu()
* Allows for the mapping for jQuery intercepted URL to a Drupal PHP function
* The Drupal PHP function will return the child field's value(s) to jQuery in JSON
*/
function ActiveField_menu($may_cache){
    $items = array();

    // debug
    drupal_set_message("ActiveField_menu($may_cache,...)");
   
    if($may_cache)
    {
        $items[] = array(
                           'path'     => 'ActiveField/field-trip',
                           'callback' => 'ActiveField_getTargets',
                           'type'     => MENU_CALLBACK,
                           'access'   => user_access('Use ActiveField'),                     
                        );
                       
    // debug
    drupal_set_message("ActiveField_menu($may_cache,...if..)");
    }
   
    return $items;
   
}

/

*
* Implementation of hook_form_alter()
*
*/
function ActiveField_form_alter($form_id, &$form)
{
   
    if ($form_id == 'field_trip_node_form')
    {
        //drupal_add_js(drupal_get_path('module', 'ActiveField'),'/ActiveField.js');
        drupal_add_js(drupal_get_path('module', 'ActiveField') .'/ActiveField.js');               
                            
    }
}

/**
*
* Called by jQuery
* Submits the parent field value and returns the child field's value(s) as a JSON
*/
function ActiveField_getTargets()
{  
    // this particular query is just for testing.
    $sql="SELECT title FROM {node} WHERE type='location'";
    $result = db_result(db_query($sql));
   
    print drupal_to_js($result);

    exit();

}

ActiveField.js

/** ActiveField.js

JavaScript file with jQuery
* Used by ActiveField.module

/

//$Id$

if(Drupal.jsEnabled)
{
    $(document).ready(function()
              {
                          // Parent field & respective event   
                          // Adding change event to Hot Spot Field
                          $('#edit-field-location-key').change(function(event)
                                                {
                                                   
                                                     // Call back function for AJAX call
                                                     var frmDrupal = function(data)
                                                           {
                                                               // convert the value from Drupal to JSON
                                                               var result = Drupal.parseJson(data);
                                                               // Set the child field(s)' value(s)
                                                               // setting the text for the "test" text field
                                                               $('#edit-field-capital-value').text(result);
                                                       
                                                           }

                                                     //AJAX call
                                                    // URL: ActiveField/field-trip     - maps to a Drupal function
                                                    // Parameters: null for now.
                                                    // Call back function:  "frmDrupal"

                                                    //The URL (i.e. the server side resource to be called)
                                                    //needs to be unique to the module                                              
                                                    $.get('ActiveField/field-trip', null, frmDrupal);
                                                    // preventing entire page from reloading
                                                    return false;
                                                });

                      });  

}

Comments

I have a similar 404 issue

mecano's picture

I have a similar 404 issue but in my case it is clear that the Ajax call is missing the drupal base path i.e. it is pointing to module/function where it should point to base_url/module/function, maybe this can help you (base url, apache root and so on).

I'm Having the same 404 issue

jniesen's picture

Hi,

I have the same issue with the base_url missing fro Ajax calls when using IE. Did you figure out what was causing this?

Thanks

James

drupal 6 ajax example

svrajput's picture

if(Drupal.jsEnabled)
{
$(document).ready(function() {

// Call back function for AJAX call
var frmDrupal = function(responseText) {
    alert (responseText); 
}

//AJAX call
$.get( url, null, frmDrupal);

// preventing entire page from reloading
return false;
})

}

A very basic Drupal & Ajax tutorial

zzadik's picture

I've recently wrote a short but helpfull (I hope :) ) step by step tutorial to set up a module that handles ajax requests.

I hope it helps other people, as I found it hard to find something similar elsewhere.

Great Tutorial

robertdev's picture

That really helped me a lot on my Ubercart dynamic catalog page, using Ajax. Please continue to provide tutorials around this, maybe with more complex scenarios.

Maybe with how you talked about the views being returned instead of the simple list.

Thanks,
Robert

Dynamically loading view via AJAX

zzadik's picture

Hi Robert,

I created another tutorial which you can find here.
It explains how to make an AJAX request, and return a view result.

I hope it is close to what you requested.

Give me a shout if you need more help.

Zion

Broken link

zzadik's picture

Sorry guys,

the link above (my first post in the discussion) is broken.
Please use the following to access the tutorial:
http://www.viziontech.co.il/tutorial1

Ajax applied to forms

polarsky's picture

Hi Zzadik,
Recently found this page and I'm grateful to you for the enlightenment that this tutorial presents. I'm new to this whole integration of drupal and ajax but I am working on a custom module that seeks to implement forms with ajax and would be glad if u guys could give me a hand.
1.There is a database containing a table which has two columns: a diagnosis and its corresponding code.
2.Now my module uses a form which takes the diagnosis and seeks to automatically populate the code field using ajax. The module is as follows:

       <?php
       /*Implement hooks for module
        *
        */
       function polarsky_help($path,$arg=NULL){
       $output = "";
       switch($path){
       case 'admin/modules#description':
       $output = "t('Implements polarsky's first form.')";
      break;
      }
      return $output;
      }
    
      function polarsky_perm(){
      $perms= array(
      'checkout form','get help');
     return $perms;
      }
    
      function polarsky_menu(){
      $items['check']=array(
      'title'=>t('Polarsky'),
      'page callback'=>drupal_get_form('myform'),
      'access arguments'=>array('checkout form'),
      'type'=>MENU_NORMAL_ITEM,
      );
      $items['check/%']=array(
      'page callback'=>'polarsky_search_code',
      'page arguments' => array(1),
      'access arguments'=>array('checkout form'),
      'type'=>MENU_CALLBACK,
      );
   
      return $items;
      }
    
    
    
    
      function myform($form_state=array(), $diagnosis=""){
      $form = array();
      if ($diagnosis){
      //take diagnosis
      $form['diagnosis']=array(
      '#type'=>'textfield',
      '#default_value' =>$diagnosis,
      '#required'=>TRUE);
    
      // assume every diagnosis has a designated code
    
      $form['code']=array(
      '#type'=>'textfield',
      '#required'=>TRUE,
      //complete this field with 'code field' in the {diagnosis} table(from the query above)
      '#default_value'=>$rep);
      $form['submit']=array(
      '#type'=>'submit',
      '#value'=>t('Submit'),
      );
      }
      return $form;
      }
      function myform_submit($form,&$form_state){
      $q="INSERT INTO {diagnosis} (name,code) VALUES (%s,%s)";
      $r=db_query($q,$form_state['values']['diagnosis'],$form_state['values'][        'code']);
      }
      function polarsky_search_code($keys){
      //Check if request is through ajax or return MENU_ACCESS_DENIED
    
      if ($_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest'){
      return MENU_ACCESS_DENIED;
      }
      $q="SELECT * FROM {diagnosis} WHERE name=%s";
      $result=db_query($q,$diagnosis);
      $final= db_fetch_object($result);
      $rep=$final->code;
      module_invoke_all('exit');
      print $search_result_string;
      die();
      }
        

     //the corresponding javascript code is implemented in a new file
     //pola.js
     91 $(document).ready(function(){
     92 $("form#myform").keyup(function(event){
     93 $.ajax({
     94         type: "POST",
     95         url: "polarsky_search_code",
     96          });
     97        });
     98  });
     99}

PS:So far this is what I have been able to do and I do not know how to go about this whole thing.Could anyone give me a hand?
How do I programatically link the form to the ajax and jQuery implementation in drupal?

Take a look at the built-in

Dave Kopecek's picture

Take a look at the built-in Drupal AHAH functions. They look a bit intimidating at first, but once you "get it" they're pretty cookie cutter.

http://drupal.org/node/331941
http://drupal.org/node/348475

The examples may talk about adding / removing form elements, but you can also change the value of existing form elements, or the contents of displayed block items.

If you don't have to many diagnosis there's always the "Old School" approach: a plain old select box could do the trick.

<select name="test">
<option value="code-1">Diagnosis 1</option>
  <option value="code-2">Diagnosis 2</option>
  <option value="code-3">Diagnosis 3</option>
</select>