Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reload AJAX from an inline link already within an AJAX page

Tags:

html

jquery

ajax

http://fh80.student.eda.kent.ac.uk/fyp/ Live example

If you see this page, click sports/venues/athletes etc it lets you browse around but it is all called in via AJAX.

This works fine but I'm having problems with inline links. For example:

Go to sports

Go to athletics

Go to "Hampden Park" link in red

This link doesn't reload within the AJAX window, it loads it in a new window...

This is the code that should set anything with the class ajaxLink as possible to load the AJAX page into the div #grid (same as the way it's done for all the other pages)

var newLink = $('.ajaxLink');
            newLink.click(function (e) {
                $.ajax({
                    url: newLink.attr('href'),
                    type: 'POST',
                    success: function (data) {
                        $('#grid').remove();
                        successHandler(data)
                    }
                });
                e.preventDefault();
            });

Here is the code for the AJAX I am using (it's long):

//on document ready
$(function () {

    var ajaxElement = $('#browserMenu a, .ajaxLink');
    ajaxElement.on('click', function (e) {
        var src = $(this).attr('href');
        console.log(src);
        //this element clicked
        var thisEl = $(this);
        var runAJAX = (src && src != '#') ? true : false;
        if (runAJAX) {
            var targetElement = $('#grid');
            var parentElement = $('#ajaxParent');
            if (src === 'index.html') {
                $('#content').load('index.html #inner-content', function () {
                    $('.selected-menu').each(function () {
                        $(this).removeClass('selected-menu');
                    });
                    thisEl.addClass('selected-menu');
                    $('#jsCode code pre').load('js/nocomments.js');
                });
            } else {
                $.ajax({
                    url: src,
                    dataType: 'html',
                    statusCode: {
                        404: function () {

                            console.log(src + ' - not found');
                        }
                    },
                    cache: false,
                    error: function (jqXHR, textStatus, errorThrown) {

                        console.log(errorThrown);
                    },
                    success: successHandler
                });
            }

            e.preventDefault();
        }

        function successHandler(data) {
            targetElement.remove();
            //remove any selected classed
            $('.selected-menu').each(function () {
                $(this).removeClass('selected-menu');
            });
            thisEl.addClass('selected-menu');
            var newContent = $('<div id="grid" />');
            newContent
                .html(data) //grab the HTML from AJAX and place it in to <div id="content"> </div>                  
            .css("opacity", "0"); //hide the div until were ready to animate it in.
            parentElement.append(newContent);
            newContent.animate({
                opacity: 1
            }, 500);
            var newLink = $('.ajaxLink');
            newLink.click(function (e) {
                $.ajax({
                    url: newLink.attr('href'),
                    type: 'POST',
                    success: function (data) {
                        $('#grid').remove();
                        successHandler(data)
                    }
                });
                e.preventDefault();
            });
        }

    });

    $('#jsCode code pre').load('js/nocomments.js');
});
like image 657
Francesca Avatar asked Dec 15 '22 01:12

Francesca


2 Answers

Why your code doesn't work

Let's step through what happens from when the user loads the page to when the user clicks on the "Hampden Park" link:

  1. User loads the page:

    The document ready event handler is called. It adds a click event handler to $('#browserMenu a, .ajaxLink'), which matches the "Sports" link inside <div id="browserMenu">. There are no elements with the "ajaxLink" class in the document at this point, so only the four menu links get this click event handler.

  2. User clicks on the "Sports" menu link:

    The click event handler from 1. is called. It loads content from the Sports page using Ajax, then passes that data to successHandler(). successHandler() removes the old <div id="grid"> and adds a new <div id="grid"> with the new content, which is a jQuery UI Tabs widget and content for the first tab (content for the other tabs are loaded using Ajax).

    At this point, successHandler() tries to add a click event handler to $('.ajaxLink'), but there are still no elements with the "ajaxLink" class in the document, so no click handlers are added.

  3. User clicks on the "Athletics" tab:

    The jQuery UI Tabs widget loads the content for the Athletics page with Ajax and displays it.

  4. User clicks on the "Hampden Park" link:

    This link has the "ajaxLink" class, but as noted in 2., it has no click event handler, so the browser opens this link normally.


A better approach

For cases where content is loaded dynamically, it is easier to use event delegation rather than trying to bind new event handlers every time the content changes.

Basically, every* event "bubbles up" from the original element where the event occurred, to its parent element, its parent's parent, all the way up to the document element. You can attach handlers to a parent element to respond to events that originate from its children.

From jQuery's documentation, you will notice that on() takes an optional selector parameter. For example, with this:

$('body').on('click', handler);

handler() will be called whenever the user clicks on the page, no matter if the user clicked on a link, an image or a blank space. When a selector is present:

$('body').on('click', 'a', handler);

handler() will only be called when the user clicks on a link (inside the body element). Any click events from elements that do not match the selector will be ignored (including any clicks that occur directly on the body element).

*As with many other cases, jQuery works around any browser inconsistencies so that event delegation works for all events.


In your case

Assuming you want one event handler to handle clicks to both menu links and content links, you can attach a click event handler to either <div class="slideWrapper"> or <body>, as they are parents / ancestors of both <div id="browserMenu"> and <div id="grid">:

$('body').on('click', '#browserMenu a, .ajaxLink', function (e) {
    // load content using Ajax
    // on success, replace old content with new
});
like image 151
Jeffery To Avatar answered Jan 12 '23 01:01

Jeffery To


You need to use the on function of jQuery to do this. Start here. click will not work with dynamic content, but the newish event API will catch dynamic content generated from an AJAX response and inserted into the DOM. This is a google example from that page:

$( "#dataTable tbody" ).on( "click", "tr", function() {
    alert( $( this ).text() );
});

What that does is catches all incoming tr elements into dataTable's tbody and give them a click event.

like image 34
Mike Thomsen Avatar answered Jan 12 '23 01:01

Mike Thomsen