Question

I am using Ajax (and jQuery, and also CoffeeScript) to load pages in a new web-site I am creating. For the navigation menu I then use the jQuery function load to load only one part of the page (namely, the content) like this (from /page1):

$( 'a' ).click ->
  $( '#container' ).load '/page2 #content'

  false

The problem with this is that I have JavaScript code in page1 (or, more correctly, in a template file) that is global on the site (due to the asset pipeline as I am using Rails 3.1). This code binds some actions to events (is this the correct jargon?) in DOM elements that are located in page2. But, as this script is run in the page that is first loaded (which easily could be page1), then the script that binds these actions to the elements will be executed in page1, and thus the DOM elements that they actually should be bound to (in page2) will not be touched.

Now, I know some ways I can fix this, but I don't like neither of them. One of these would be to put this action/event binding into a function, and then call this method after loading page2 with Ajax, but this would require me to either have introduce a special case in my page loading logic where I load the binding function after page load to bind the elements, or to have a script in the page2 content where I call the function.

I would rather not go with the former approach, as I have a more general way of loading pages (by using the <a> tag's href attribute), and introducing special cases on page load just uglifies it all. The latter solution is a rather nicer one I believe, but I would hate to put <script>tags into the content of the page that I am retrieving. I like separating content from behaviour and all that, and I feel that this might be mixing it all up a bit.

So, what I really want to know here is whatever would be a good way to solve this problem. If anyone out there knows how to go about doing this, then I would welcome any suggestions.

Was it helpful?

Solution

You might want to look into jQuery's live() event binding.

Events bound with live() are applied to retrospectively added DOM elements as well, which should solve your problem.

Edit: To be precise, live() binds to $(document) and checks the target attribute of events that have bubbled all the way up through the DOM – that's why the binding works even when elements are added after binding the event callback.

Example HTML:

<div id="some_triggers">
    <a id="foo" href="#">Foo!</a>
</div>

Example jQuery:

$('#foo').click(function(){ alert('foo') });
$('#bar').click(function(){ alert('bar') });
$('#some_triggers').append('<a id="bar" href="#">Bar!</a>');
$('#foo').live('click', function(){ alert('foo live()!') });
$('#bar').live('click', function(){ alert('bar live()!') });

// -> clicking #foo alerts "foo" and "foo live()"
// -> clicking #bar alerts "bar live()" only, since the '.click()' binding doesn't work on non-existent DOM elements.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top