Pedro Posada | Asynchronous content loading in Drupal

Asynchronous content loading in Drupal

Posted on March 31, 2008 - 5:51pm
<< 45 of 50 >>

This is a recipe that I used to load the content of my "Portfolio of Websites" page. I took advantage of jQuery and Drupal menu system to generate an asynchronous http request, serve the content and show it inside a div tag.

This is the module code:

.info file

; $Id: asynch.info,v 1.0 2008/02/24 14:07:53 pposada Exp $
name = Asynchronous Loading of content from any page
description = Helper module to load page output asynchronously.
package = Custom
dependencies = pagearray
; recommended = jquery_interface jquery_update

.module file

<?php
/**
* Implementation of hook_perm()
*/
function asynch_perm(){
    return array(
'load content asynchronously');
}


/**
* Implementation of hook_menu()
*/
function asynch_menu($may_cache){
   
$items = array();
    if (
$may_cache) {
       
$items[] = array(
           
'path' => 'asynch/load',
           
'callback' => 'asynch_printer',
           
'type' => MENU_CALLBACK,
           
'access' => user_access('load content asynchronously'),
        );
    }
    return
$items;
}

/**
* Called jQuery
* This submits a request to asynch/load page and returns the content part of the page
*/
function asynch_printer($nid){
   
$path = "node/".$nid;
     
$return = pagearray_page($path);
      print
drupal_to_js(array('content' => $return['page']['content']));
    exit();
}
?>

php snippet that goes inside the page body:

<?php
//jquery_interface_add();

// jquery content loader
drupal_add_js(
   
'$(document).ready(function(){
         $(".view-item-work-sample").css("cursor","pointer");
        
         var first = $("#dynamic-filter-work_sample").find(".view-data-node-nid:first").text();
         $("#placeholder").html("<center><img src=\"/sites/all/themes/pedroposada/images/ajax-loader.gif\" align=\"center\"></center>");
            
         $("#placeholder").load("/asynch/load/" + first, function(){
            var result = Drupal.parseJson($("#placeholder").html());
            $("#placeholder").html(result["content"]);
            $(".ws-thumb > img").mouseover(function(){
                var source = "/files/imagecache/sample_big/files/" + $(this).attr("alt");
                $(".ws-big > img").attr("src",source);
            });
            $("#placeholder").attr("title",first);
           
         });

         $(".view-item-work-sample, .view-item-work-sample-side").click(function(){
           var path = $(this).find(".view-data-node-nid").text();
          
           if($("#placeholder").attr("title") != path ){
            
             $("#placeholder").html("<center><img src=\"/sites/all/themes/pedroposada/images/ajax-loader.gif\" align=\"center\"></center>")
            
             .load("/asynch/load/" + path, function(){
               var result = Drupal.parseJson($("#placeholder").html());
               $("#placeholder").html(result["content"]);
               $(".ws-thumb > img").mouseover(function(){
                var source = "/files/imagecache/sample_big/files/" + $(this).attr("alt");
                $(".ws-big > img").attr("src",source);
               });
               $("#placeholder").attr("title",path);
              
             });
           }
           return false;
         });
        
          
      });'
,
   
'inline'
);
?>


<div id="placeholder">
</div>

This is just one more example of how you can implement the jQuery and Drupal to load content asynchronously.

Submitted by Anonymous on May 20, 2008 - 1:18pm.

This is a great idea. I am trying to get it to work on my site, but the directions are a bit too thin for me to actually get it running. Could you give some more details?

For instance, your calling path =/asynch/load/ , but make no mention as to what the directory is for or that one should create it.....?

Submitted by pedro on May 23, 2008 - 11:33am.

Basically you just need to create a menu item in the module as explained there. When you use the hook_menu, you create there a new menu item that will call the function. Every menu item is a page in drupal, this menu item I created here is the page that generates the JSON code which then gets parsed by jQuery and renders the content.

I hope this is what you were asking for.

Submitted by Anonymous on May 28, 2008 - 12:17pm.

Im sorry, I just don't understand. I am obviously missing a step. Here is what I am doing:
- Creating a module folder that contains the .module and .info files.
- Enabling the module in admin.
- Creating a Page with the PHP snippet above and selecting "PHP code" from the "input format" drop down.

From this point on I am lost.

Submitted by pedro on May 28, 2008 - 2:35pm.

Ok, you will need to make sure that all the HTML tags have the correct "class" and "id" on the page you are creating.

You can take a closer look at my Portfolio of Websites page to check if you are using the correct ids and classes for the links. You can test this by just creating one link on your page.

You can see that I am using:

$(".view-item-work-sample, .view-item-work-sample-side").click(function(){});

You need to use these same classes so that when you click on those tags you will send the http request.

Please tell me what happens when you click on you links.

Submitted by Anonymous (not verified) on May 28, 2008 - 2:56pm.

I had originally copied the links from your portfolio page and replaced your node numbers with my own. When I click on one of the links, the loading gif appears, which shows that its obviously triggering something, however the node never appears.

As far as I can tell all of the classes and ids do indeed match consistently.

Submitted by pedro on May 28, 2008 - 3:20pm.

Well, I would try just returning a string first. Instead of loading a whole node, try returning the same string . I remember that happened to me first but I am not sure how I fixed it. Instead using the page array just return a simple string. I hope you get it working.

Submitted by Anonymous (not verified) on May 28, 2008 - 4:48pm.

Where exactly would I make the change to load something other than a node? I have a tried everywhere I can think of and nothing seems to change the outcome.

I had noticed that on your portfolio page you have some javascript that seems to be required, but isn't mentioned in your recipe here. Perhaps theres something else missing from here as well?

Submitted by pedro on May 29, 2008 - 2:24am.

You need to change:

<?php

/**
* Called jQuery
* This submits a request to asynch/load page and returns the content part of the page
*/
function asynch_printer($nid){
   
$path = "node/".$nid;
     
$return = pagearray_page($path);
     
//print drupal_to_js(array('content' => $return['page']['content']));
     
print "my string";
    exit();
}
?>

note the "my string"

Submitted by Anonymous (not verified) on May 29, 2008 - 9:48am.

yeah, I had already tried that but wasn't sure. The string isn't returned.
What part of the code is actually communicating with the module? I noticed that if I disable the module, nothing seems to change.

Submitted by pedro on May 31, 2008 - 9:21pm.

The part that communicates with the module is the load() function in the jQuery code snippet.

That function sends a http request to the module and the module returns the string.

The string is encoded using the drupal_to_js()

Submitted by Anonymous (not verified) on June 3, 2008 - 11:19am.

I have tried everything I can think of to get this thing to work, but with no luck.

If you could offer any further information or suggestion I would be very grateful. Otherwise, Im going to have to abandon this idea.

Submitted by pedro on June 4, 2008 - 11:06am.

I took a look at my code again to make sure nothing was missing in this post.

Make sure you have the "jquery update" module installed and the latest version of jquery.js in your drupal installation.

Submitted by Anonymous (not verified) on June 9, 2008 - 11:36am.

ahh... that would explain how you had a different version of jquery than I originally did. I had before manually included the newest version without the jquery update module, I have now added this module as you suggested, but there is still no change.

What does this refer to : "asynch/load/"?
When I browse to that directory on your server I see a bunch of content;
"...=\"last taxonomy_term_4\"\x3e\x3ca href=\"/category/blog/phpscripts\" rel=\"tag\" title=\"\" class=\"taxonomy_term_4\"\x3ephp scripts\x3c/a\x3e\x3c/li\x3e\n\x3c/ul\x3e\x3c/span\x3e\n \x3cdiv ..."

However, when I browse to that directory on my site, I get a "page not found" error. This is expected since I don't have that folder in my root directory. Can you shed some light on this?

Submitted by pedro on June 9, 2008 - 11:55am.

That is exactly what you are missing. It seems that you have not created the menu item correctly in your module.

There is no actual folder on the server. There is a function that gets called when you type that address in your browser.

Take a look at my code again under "Implementation of hook_menu()" and you will see "asynch/load" there. That's the drupal path to call the function that generates the actual content. The jQuery script sends a request to that path and retrieves the content. There is no actual directory on the server.

Submitted by Anonymous (not verified) on June 9, 2008 - 12:04pm.

Ok, so what exactly am I suppose to edit in that part of the module?

Submitted by pedro on June 9, 2008 - 2:05pm.

Have you checked the access permissions? You need to give access to the anonymous user to your module. Its called "load content asynchronously".

Submitted by Anonymous (not verified) on June 9, 2008 - 2:59pm.

I don't actually see the module appear in the access control page. The module is active though.

Submitted by pedro on June 16, 2008 - 10:07am.

Take a look at this function here:

<?php
function asynch_perm(){
    return array(
'load content asynchronously');
}
?>

this hook creates an entry in the access control page for this module. This module is supposed to show up in that page. Go to "admin/user/access" and check again and make sure that "anonymous user" has access to it.

Post new comment

The content of this field is kept private and will not be shown publicly.
Please solve the math question. This way we will know you are not a robot.