views:

428

answers:

2

I'm not sure what to call this question, since it involves a variety of things, but we'll start with the first issue...

I've been trying to write a simple to use jQuery for includes (similar to php or ssi) on static html sites. Whenever it finds div.jqinclude it gets attr('title') (which is my external html file), then uses load() to include the external html file. Afterwards it changes the class of the div to jqincluded

So my main index.html might contain several lines like so:

<div class="jqinclude" title="menu.html"></div>

However, within menu.html there might be other includes nested. So it needs to make the first level of includes, then perform the same action on the newly included content. So far it works fine, but it's very verbose and only goes a couple levels deep.

How would I make the following repeated function to continually loop until no more class="jqinclude" elements are left on the page? I've tried arguments.callee and some other convoluted wacky attempts to no avail.

I'm also interested to know if there's another completely different way I should be doing this.

 $('div.jqinclude').each(function() { // begin repeat here
  var file = $(this).attr('title');
  $(this).load(file, function() {
   $(this).removeClass('jqinclude').addClass('jqincluded');
   $(this).find('div.jqinclude').each(function() { // end repeat here
    var file = $(this).attr('title');
    $(this).load(file, function() {
     $(this).removeClass('jqinclude').addClass('jqincluded');
     $(this).find('div.jqinclude').each(function() {
      var file = $(this).attr('title');
      $(this).load(file, function() {
          $(this).removeClass('jqinclude').addClass('jqincluded');
      });
     });
    });
   });
  });
 });
+1  A: 

You can wrap it in a recursive function like this taking advantage of the context part of the selector:

function doIncludes(context) 
{
  $('div.jqinclude', context).each(function() { // begin repeat here
    $(this).load($(this).attr('title'), function() {
      $(this).removeClass('jqinclude').addClass('jqincluded');
      doIncludes($(this));
    });
  });
}
$(function() {
  doIncludes(document);
});

This looks for includes starting in document overall, then recurses, looking only in the content just loaded each time.

Nick Craver
Hey Nick - thanks for your time. I'm also trying to figure out how your version is different than Cletus'. Other than his removing the class before the .load() - it seems that you both are executing a callback function within the load.
brandonjp
@brandonjp - Both should work, his answer wasn't on the callback when I left the comment, it's since been updated. The current difference is his isn't adding the `jqincluded` class like your question was, this answer still is....if you don't need it though, just remove the `.addClass('jqincluded')`
Nick Craver
+1  A: 

Try this:

$("div.jqinclude").each(load_include);

function load_include() {
  $(this).removeClass("jqinclude").load($(this).attr("title"), function() {
    $(this).find("div.jqinclude").each(load_include);
  });
}

The way this works is that it finds each div to be loaded and loads them. When that load is complete the contents of that div are checked for more divs to include because you don't need to check the whole document then, only the new content.

This should load everything.

cletus
I don't think this will work, as the ajax callback will take some time to complete
Nick Craver
Nick, are you saying that because of the time required for the ajax callback, it might not load quick enough to manipulate the loaded content? So far, both of your answers seem to be working flawlessly, but I'm only loading very small html files locally at the moment.
brandonjp