Show/hide details of only one row

Show/hide details of only one row

manentiamanentia Posts: 14Questions: 0Answers: 0
edited July 2010 in General
Using the example here http://datatables.net/examples/api/row_details.html I've got very nice details shown for each of my rows, but I'd like only ONE details row to be shown at a time (and all closed rows should have their icons reflect their state). Also, the user should be able to close the open details row, reverting the table back to its initial state (this other example keeps the last detail row shown http://datatables.net/forums/comments.php?DiscussionID=1610)

[code]
$("td", oTable.fnGetNodes()).delegate("img", "click", function () {
var nTr = this.parentNode.parentNode;
if (this.src.match('icon-close')) {
/* This row is already open - close it */
this.src = "/images/icon-add.png";
oTable.fnClose(nTr);
var temp1 = oTable.fnGetData(nTr);
/* only update cell if data has changed */
if (schoolsList != temp1[4]) {
oTable.fnUpdate(schoolsList, nTr, 4, true);
$("td:nth-child(4)", nTr).effect("pulsate", { times: 3 }, "slow");
}
}
else {
/* Open this row */
this.src = "/images/icon-close.png";
oTable.fnOpen(nTr, fnFormatDetails(nTr), 'details');
var temp2 = oTable.fnGetData(nTr);
schoolsList = temp2[4];
}
});
[/code]

Replies

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    I think it looks like you are nearly all the way there already. Combining a little of the Javascript in the thread you linked to with what you have here, and hopefully it's done. You could add something like the following to your 'else' condition:

    [code]
    /* Close any rows which are already open */
    $("td img", oTable.fnGetNodes()).each( function () {
    if ( this.src.match('icon-close') ) {
    oTable.fnClose( this.parentNode.parentNode );
    }
    });
    [/code]
    It will look for any open rows and close them. You might want to add in some of the logic that you use in the closing part of your code - I'm not sure what you would want the functionality to be :-)

    Regards,
    Allan
  • manentiamanentia Posts: 14Questions: 0Answers: 0
    That works! I knew I was close. Oh, and in the code you gave, adding one line will put the icon back where it should be:

    [code]
    /* Close any rows which are already open */
    $("td img", oTable.fnGetNodes()).each(function () {
    if (this.src.match('icon-close')) {
    this.src = "/images/icon-add.png";
    oTable.fnClose(this.parentNode.parentNode);
    }
    });
    [/code]
  • manentiamanentia Posts: 14Questions: 0Answers: 0
    No further problems, but I wonder what your thought is on using .delegate()
    [code]
    $("td", oTable.fnGetNodes()).delegate("img", "click", function () {
    //whatever
    });
    [/code]
    instead of your example
    [code]
    $('td img', oTable.fnGetNodes()).each(function () {
    $(this).click(function () {
    //whatever
    });
    });
    [/code]
    For some reason I chose to use .delegate() but it adds about 10% to execution time... so I'll go back to your example. :) Thanks again.
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    To be honest I've never really used delegate very much. This is an interesting post about it: http://mytechworld.officeacuity.com/?p=592 . One of the draw backs with the method is that it isn't live (ie. add new elements and they won't have the event bound to them). As for the difference between live() and delegate() - the article linked does a better job of explaining than I could :-)

    Regards,
    Allan
  • PEhrlichPEhrlich Posts: 5Questions: 0Answers: 0
    edited July 2010
    From the jQuery docs, delegate will:

    "Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements."

    Meaning that it is live. The cool thing about it is that it creates one handler, which is fired from any element scoped by the *immediately* preceding selector. In comparison, live or bind create one handler for every element, clunky for many rows. This makes delegate an extremely useful tool for DataTables!

    Here's an example from what I've just been working on. The handlers work great, but for some reason the event does not get stopped as one would imagine. Any thoughts on the issue would be most helpful!

    [code] $dt_<%= table_name %>.delegate('tr.data_row a', 'click', function(e){ // ruby
    alert('a click!');
    e.stopImmediatePropagation();
    });

    $dt_<%= table_name %>.delegate('tr.data_row', 'click', function(e){ // ruby
    alert('row click!');
    });
    [/code]

    The anchor alert shows first, followed by the row alert. Gah.

    PS: This is my first post. DataTables is the bomb! wooooo!


    Edit: Had a friend look at the code. As far as I can tell, it looks like a JQ bug, which seems hard to believe, but might be true.. Here's my workaround, which is perhaps even better:

    [code] $dt_<%= table_name %>.delegate('tr.data_row', 'click', function(e){
    if ( !$(event.target).is("a") ){
    console.log(e); //do stuff etc
    }
    });[/code]
  • MikeSMikeS Posts: 113Questions: 1Answers: 0
    Hi PEhrlich,

    I'm the first to admit that I'm a JQ noob, but, have you tried e.stopPropagation(); instead of e.stopImmediatePropagation(); ?

    Just a thought.
  • PEhrlichPEhrlich Posts: 5Questions: 0Answers: 0
    Step 1: Read the docs:
    http://api.jquery.com/event.stopImmediatePropagation/

    "In addition to keeping any additional handlers on an element from being executed, this method also stops the bubbling by implicitly calling event.stopPropagation()."

    Step 2: Check the source:
    http://www.bit.ly/jqsource

    [code]stopImmediatePropagation: function() {
    this.isImmediatePropagationStopped = returnTrue;
    this.stopPropagation();
    },[/code]

    Being a noob is fine. The important part is knowing how to learn well.
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    edited July 2010
    Hang on - let's not go down this route on this forum please. MikeS was being helpful, and indeed the differences between stopPropagation and stopImmediatePropagation can be very useful and are worth knowing the merits of each and when to apply them (thanks for the information PEhrlich).

    We are all learning on the forum (me more that most I'm sure :-) ), so let's keep it courteous. I'll leave this conversation open for now in the hope that we will return to talking about the merits of jQuery delegates, live and so on. It will be closed if it deviates...

    Regards,
    Allan
  • PEhrlichPEhrlich Posts: 5Questions: 0Answers: 0
    D'oh! I didn't mean that in a bad way at all! I see how it totally came across negatively, but I was really just trying to share (teach a man to fish, etcetc). My bad, and thanks for leaving the thread open :-)
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    No problem PEhrlich - thanks for clearing it up :-). It's a great community we've got going here, with people such as yourself sharing wisdom from the jQuery source, MikeS helping people out (and asking a few cracking questions / finding bugs!). I'm personally very proud of what we've got going on here - let's kept it going!

    Thanks for your kind words about DataTables in your earlier post btw :-)

    Going back to delegates - they do look like they have a lot of advantages over other methods when tying an event handler to many elements (not uncommon in a DataTable). Just a thought, but have you tried returning boolean false from the first event handler? jQuery tends to follow something like the MSIE (old) pattern of dealing with bubbling and basing it on the return of the event handler function.

    Regards,
    Allan
  • PEhrlichPEhrlich Posts: 5Questions: 0Answers: 0
    edited July 2010
    So looking at the code is a new trick i just learned (thanks slideshare!*), and its cool!

    [code] var ret = handleObj.handler.apply( this, arguments );

    if ( ret !== undefined ) {
    event.result = ret;
    if ( ret === false ) {
    event.preventDefault();
    event.stopPropagation();
    }
    }

    if ( event.isImmediatePropagationStopped() ) {
    break;
    }[/code]

    In short, returning false does the same as returning false in the onclick attr, which in this case prevents the link from being clicked on at all. I suppose the real challenge now would be figuring why stopPropagation doesn't have the desired effect on delegate, but for now I'm happy leaving it for another day ;-)

    *http://paulirish.com/2009/perf/
  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    I tried it with the following code and it had the desired effect (no second alert - assuming I understand the problem correctly):

    [code]
    $('#example tbody').delegate('tr td', 'click', function(e){
    alert('click 1');
    return false;
    });

    $('#example tbody').delegate('tr td', 'click', function(e){
    alert('click 2');
    });

    $('#example').dataTable();
    [/code]
    I've been keeping a copy of jQuery.js on my desktop to look things up when things go funny. I like their method of dealing with isImmediatePropagationStopped(). Smooth.

    Regards,
    Allan
  • PEhrlichPEhrlich Posts: 5Questions: 0Answers: 0
    Returning false does indeed stop the second listener, but the downside is that it prevents the default action (in this case, the browser following the href.) Therefore some default action of the event fires the second listener, even when propagation has been stopped. Odd.
  • carlotorcarlotor Posts: 5Questions: 0Answers: 0
    hi menantia.
    you already read this discussion, for help..


    Krl
This discussion has been closed.