tags:

views:

29

answers:

2

I am using jQuery to load the search results from a php class when the user enters a search term. The problem is that jQuery runs and executes the functions as required the first time round on the main page, but when the user enters a search keyword and the results are loaded from the class file on the same page via ajax, jQuery does not execute the function required.

What I want to do is, when the search results are loaded on the main page, it should only show the Quote and the author, not the arabic and reference. When the user clicks on the Quote, it should act like an accordian, toggling the div container of arabic and reference.

However, while jQuery works great loading the results from the class file, it doesn't execute to hide the container of arabic and reference when it's loads the search results nor does it run the click event when the user clicks on the Quote to show the container, as firebug shows.

index.php:

    <script type="text/javascript">
    $(function() {

                $(".bsearch")
                    .keydown(function() {
                         //create post data
                          var postData = { 
                            "search" : $(this).val()
                          };

                          //make the call
                          $.ajax({
                            type: "POST",
                            url: "quotes_in.php",
                            data: postData, //send it along with your call
                            success: function(response){
                                $("#left").html(response);
                            }
                          });

                    }),




                $("div#smore").hide();
                    //toggle the componenet with class msg_body
                $("p#s_quotes").click(function()
                    {
                      $(this).next("div#smore").slideToggle(200);
                    }),         



                });

    </script> 

 <!-- Begin Left Column -->
        <div id="left">

        </div>
<!-- End Left Column -->

Quotes_in.php:

include_once "inc/class.quotes.inc.php";
$quotes = new Quotes($db);


if (isset($_POST['search'])) 
    $quotes->searchQuotes();

The function in the class file which formats the search:

   ---SQL QUERY for SEARCH---
    public function formatSearch($row, $search) 
                {


                    return "<div class=\"swrap\">"
                    . "<p id=\"s_quotes\">&nbsp;" . $cQuote . "&nbsp;</p>"
                    . "<div id=\"smore\"><p id=\"s_arabic\">" . $this->h($row['cArabic']) . "</p>"
                    . "<p id=\"s_reference\"><span class=\"source\">Source:</span> " . $this->h($row['vReference']) . "</p></div>"
                    . "<p id=\"s_author\"><b>-</b>&nbsp;" . $this->h($row['vAuthor']) . "</p></div>"; 
                }
+3  A: 

It's becasue your quote elements are being replaced, so you need to use .live() or .delegate() handler here, instead of this:

$("p#s_quotes").click(function() {
  $(this).next("div#smore").slideToggle(200);
});         

You need this:

$("p#s_quotes").live('click', function() {
  $(this).next("div#smore").slideToggle(200);
});    

Unlike .click() which binds an event handler to the element, which is getting replaced...and so the event handler vanishes too, .live() adds an event handler to document which listens for a click from p#s_quotes (this can be just #s_quotes) to bubble up, and executes the handler if that happens.


For the hiding portion, either call $("#smore").hide(); again in your success callback, or create them hidden, like this:

<div id=\"smore\" style='display: none;'>
Nick Craver
ah, thanks for the explanation. that makes sense.
fuz3d
+2  A: 

The important thing to remember when you attach events on JQuery is that it is running at that moment, for the current state of the DOM, and will not necessarily apply for any elements that are added to the DOM in the future.

To attach events to objects that may not exist yet (along with items that already do exist, use the live() function, like so:

        $("p#s_quotes").live("click", function()
                {
                  $(this).next("div#smore").slideToggle(200);
                }),

By using live(), jQuery will monitor for new elements as they are added to the DOM, and if they match your selectors, will apply the correct handler to them.

Ryan Brunner
This is incorrect, `.live()` does not listen for new elements or apply handlers, it works in an entirely different way, see my answer for a brief description.
Nick Craver
@Nick Craver - No offense, but Ryan Brunner said EXACTLY what you said, just in a less proficient and professional manner, however he's still right, but so are you...
webfac
@webfac - No, he didn't, this portion is incorrect: "jQuery will monitor for new elements as they are added to the DOM, and if they match your selectors, will apply the correct handler to them". I said it applies an event handler, *one* event handler, to `document`, which is correct. It does not look for new elements and attach handlers in any way.
Nick Craver
Fair enough - I didn't realize how this was implemented internally. It's really an implementation detail, however - functionally it's equivalent to attaching event handlers to new elements.
Ryan Brunner
@Ryan - It's not, for several reasons, event bubbling will affect `.live()` differently, e.g. anything stopping an event before it gets to `document`, there are several potentially important differences. What you're thinking of is the `.livequery()` plugin (around before `.live()`) which *does* look for new elements and attach handlers.
Nick Craver
I actually wasn't aware of the liveQuery plugin, I'm just describing what the functional behaviour is for the majority of non-edge case scenarios. Even jQuery.com describes `live()` as "Attach a handler to the event for all elements which match the current selector, now or in the future." For a beginner to jQuery, this is a much less opaque description of `live()`s functionality than the actual implementation.
Ryan Brunner