I'm new to AJAX + Drupal, I can't solve the following simple problem, please advise.
I have a table with people names and ages. I'd like to list the names of people on the page, by default ordered by name. Then if the link 'sort by age' is pressed, they should be listed by age without page reload.

My module:

drupal_add_js("./sites/default/modules/my_module/my_module.js");

function my_module_menu() {
  $items['my_module'] = array(
    'page callback' => 'my_module_all',
    'type' => MENU_CALLBACK,
    'access arguments' => array('access content'),
   );
  return $items;
}

function my_module_all(){

	if (isset($_POST['ord'])) $ord = $_POST['ord']; else $ord = 'name';

	global $page_content;

	$page_content .= "<div id=\"mydiv\">";
	$page_content .= "<a href='#' class='order_button' id='name'> sort by name </a>";
	$page_content .= "<a href='#' class='order_button' id='age'> sort by age </a><br>";	

	$list = get($ord);
	
	$page_content .= $list."</div>";	

// does not matter if I comment it out or not
/*
       if(isset($_POST['ord'])) {
             header("Content-type: application/json");
             drupal_to_js($list);
	}
*/	
	return $page_content;	

}

// returns the name of people ordered by name or age
function get($ord){
	// simple table with 2 columns: name, age
	$query = "SELECT name FROM people ORDER BY %s";
	$result = db_query($query, $ord);
	while ($objects = db_fetch_object($result)) {
			$list .= $objects->name."<br>";
	}
	return $list;
}

And my js:

Drupal.behaviors.my_module = function(context) {
  $('a.order_button:not(.mymodule-processed)', context).addClass('mymodule-processed')
  .bind('click', function(){
    $.post('my_module', {"ord": this.id}, callback_result);
    return false;
  });
}

var callback_result = function(response) {
  var result = Drupal.parseJson(response);
  $('#mydiv').html(result.data);  //works only with 'data' written
}

Comments

larowlan’s picture

You might be best to use views for this.
It has a table style plugin that supports click sorting on the headers and supports ajax.
If you're defining your own tables, you need to implement hook_views_data to let views know about your table's fields.
Aside: you should prefix your function and table names with that of your module to avoid namespace collisions.

Lee Rowlands

--author="larowlan <larowlan@395439.no-reply.drupal.org>"
Csabbencs’s picture

Thanks for the reply. Views might be a good solution, I'll definitely check that.
But for now, I'd rather stick to my version to get to know how things work when using drupal for ajax.

I did some small modificatons that you can see in the code above and it started working almost as I expected. Though I'd like to point out some things I totally don't understand:
1., After you click, not the expected result ($list .= $objects->name) is put into "mydiv", but the whole page ($page_content).
2., The code part commented out has no influence on the result.
3., The code stops working if I leave out "data" from the following javascript line: $('#mydiv').html(result.data);

2 and 3 are the most mysterious.

Could you help please?

duckzland’s picture

can you try returning $list instead of $page_content and see what happen?

--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com

Csabbencs’s picture

$list holds only the records from the database.
$list is part of the page content, but page content is more than just a list, so $list is not sufficient to return.

duckzland’s picture

yes but did the $list successfully returning data via ajax?.

as I see in the code you didn't load any more content data aside $list?

Anyway, if the $list is returning data correctly via ajax, you can add more data to $list like node_load($nid) result for additional content.

--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com

Csabbencs’s picture

I did load other content data into the page: there are 2 links that you need to press to start ajax:

$page_content .= "<a href='#' class='order_button' id='name'> sort by name </a>";
$page_content .= "<a href='#' class='order_button' id='age'> sort by age </a><br>";	

If I return $list only, nothing happens since the links that would start ajax are gone. (In this case, only the list of records are there without any capability being sorted by ajax.)

duckzland’s picture

can you change this

return $page_content; 

to

drupal_json(array('data' => $page_content));

and

var result = Drupal.parseJson(response);

to

var result = Drupal.parseJson(response.data);
}

and see what happen?

--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com

Csabbencs’s picture

I tried.
Without returning $page_content, the resulting page gets pretty ugly due to drupal_json(array('data' => $page_content));
It will be a blank white page outputting only the following : { "data": " ..." }

graysadler’s picture

Could you just print the $page_content instead of returning it?

Lead Developer and Founder of StreamRiot.com

Csabbencs’s picture

If I do it, all drupal html stuff is gone, the page is showing only what I put in the variable: 2 links and the list of records.

duckzland’s picture

"It will be a blank white page outputting only the following : { "data": " ..." }"

That is the right way, now you need to "attach" the "{"data" : "...."} to the div area in your content using jQuery

--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com

Csabbencs’s picture

I don't get it. Could you be a bit more specific?
You mean the function callback_result? That's already in the code.

duckzland’s picture

I mean u need to tell the js to grab the data and attach it to the div element that you wish to update.

example ajax jquery code :


    var updateProducts = function(response) {
               $('.MyDIv').append(response.data); // change mydiv to whatever your div element is 
               Drupal.attachBehaviors(response.data); // to make sure that the new element js is reattached again, careful double event bubbling may occur
           };
           $.ajax({
	      type: 'POST',
	      url: Put_your_call_back_url_here,
	      success: updateProducts, 
	      dataType: 'json', 
	      data: ({ 'number' : page , 'json' : 1})  //Pass a key/value pair that you can get in php using $_POST
	    });

--------------------------------------------------------------------------------------------------------
if you can use drupal why use others?
VicTheme.com

Csabbencs’s picture

My code is also from an example and I checked a lot of examples otherwise I wouldn't have come here to ask.
What you suggest is the same I put in my code: $.post('my_module', {"ord": this.id}, callback_result);
(By the way I tried yours and didn't work)
I wouldn't think that I'm very lame, but for now let's suppose I am.
Could you please either try out my original code up above and find the bug or send your own working solution without pseudo code?

I'm starting to feel that the time we both spent on this issue is much more than I would have needed to write the code without Drupal...

jason_gates’s picture

Hi,
Drupal comes with built-in table sort mechanisms. Try this:

function my_module_menu() {
  $items['test/sort_table'] = array(
    'page callback' => 'my_module_all',
    'access arguments' => array('access content'),
    'title' => 'A Simple Sortable Table',
    'type' => MENU_CALLBACK | MENU_NORMAL_ITEM,
  );

 return $items;
}


function my_module_all() {

  $header = array(
      array('data' => t('Name'),'field' => 'name'),
      array('data' => t('Age'),'field' => 'age'),
  );

  $rows['data'] = array(); 
  $query_count = "select count(name) from {people} ";
  $sql = "select b.name as name, age from {people} ";
  $result = db_query($sql .  tablesort_sql($header) );

  if ($result) {
    while ($row = db_fetch_object($result)) {
        $rows[] = array($row->name, $row->age);
    }
  }
   
  return theme('table', $header, $rows);
}

Note! In your original post, please nix the php statement that is not placed inside a function:
NIX -> drupal_add_js("./sites/default/modules/my_module/my_module.js");

Recommendation: If you are new to programming in general, I would recommend "walk then run". Most beginning programmers can not describe the difference between synchronous and asynchronous. Ajax is not a "beginners" task. In other words, see if my example helps :) It should at least get you started.

In addition, your database table should contain a primary key (unique identifier). If you are using MySql with Drupal your hook_schema implementation includes 'type' => 'serial', to define a primary key. A table with just name and age fields is not going to work very well. However, for a very limited "proof of concept", it will do :)

That's all you need.
Hope that helps :)

Csabbencs’s picture

Thanks for the reply!
I agree regarding "walk then run". :)
I completely understand your example and, of course, I can do and I'm already done sorting the table this way.
In my case the point is AJAX. I'd like to do the sorting without page refresh.
Could you please extend YOUR example so that no page refresh happens? That might help me a lot!