Meaningless Drivel is fun!*
The moose likes HTML, CSS and JavaScript and the fly likes Need Help with binding click events to table rows Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » HTML, CSS and JavaScript
Bookmark "Need Help with binding click events to table rows" Watch "Need Help with binding click events to table rows" New topic
Author

Need Help with binding click events to table rows

Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Hi

I am using jquery and I am trying to bind events to my table rows.


I thought of doing something like this:

$("#chk_EntireRow1").click(function() { checkRow("#chk_EntireRow1", "#tr_selectRow1"); });

But I am going to have ton's on these and these could keep growing so I don't want to keep copying and pasting the code over and over again.

So I decided to try a for loop.



But this does not work and I am not sure why. Like all the events get binded with the last Identifer.

So I have a 11 rows. so my ID would be "#chk_EntireRow1" through 11. and "#tr_selectRow1 through 11".

But it seems like I get this.

First Row: #chk_EntireRow11, #tr_selectRow11
Second Row: #chk_EntireRow11, #tr_selectRow11
.
.
.
Last Row: #chk_EntireRow11, #tr_selectRow11

So they all seem to get the last value. So am I understanding something wrong.

I thought this loop would go through 11 times and bind 11 different click events to a 11 different table rows.

Here is the generated output


[ June 11, 2008: Message edited by: Bear Bibeault ]
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

I am using jquery and I am trying to bind events to my table rows.
Actually, it looks like you're binding them to checkboxes. Which did you intend?

In any case, rather than apply the listener to each row (or checkbox) individually, it'd be a lot easier and much more efficient to just apply a single handler to all rows. Something like:

Within the handler, the element that triggered the event will be available as the function context (this), so there's no need to have to pass individual ids as you were attempting. Once you have the target element, you can use the jQuery selectors and methods to find any related element (parent, siblings etc) if necessary.
[ June 11, 2008: Message edited by: Bear Bibeault ]

[Asking smart questions] [Bear's FrontMan] [About Bear] [Books by Bear]
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

P.S. When posting please remove those gawd-awful long Base64 state variables that are being generated. Those long lines really boof up the formatting of the posts and aren't germane to any discussion.
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Originally posted by Bear Bibeault:
Actually, it looks like you're binding them to checkboxes. Which did you intend?

In any case, rather than apply the listener to each row (or checkbox) individually, it'd be a lot easier and much more efficient to just apply a single handler to all rows. Something like:

Within the handler, the element that triggered the event will be available as the function context (this), so there's no need to have to pass individual ids as you were attempting. Once you have the target element, you can use the jQuery selectors and methods to find any related element (parent, siblings etc) if necessary.

[ June 11, 2008: Message edited by: Bear Bibeault ]


Well what I was trying to do was this. The first checkbox is the one that checks the entire row. So when this is clicked the it has the id's of all the other checkboxes in that row and they get checked.

However I like your id but I am not sure how to pull it off.




So what I need to is first make ID for the table. Then this will find all table rows in that table with that ID.

So this is what I have so far.

Not working yet though.

Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67


One of the problems with doing things this way is that you lose the function context (this) when you simply call another function from the listener. Why bother to define a separate named function? The only time I'll create a named function is when it needs to be explicitly called from more than one place.

Rather, put the code directly in the listener.

So your function has a number of problems. First, "this" is no longer the target element. Another problem is your use of this selector "td > input:checkbox" which selects all input checkboxes that are direct children of <td> elements. Any this-ness is not accounted for (even if this pointed to the right thing).

Is that enough of a clue to loosen things up?

Hint: the parent() or parents() methods may prove helpful.

Also remember that you can limit a selector expression to a subtree of the DOM by passing the subtree root as the second parameter to $().
[ June 11, 2008: Message edited by: Bear Bibeault ]
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Originally posted by Bear Bibeault:

One of the problems with doing things this way is that you lose the function context (this) when you simply call another function from the listener. Why bother to define a separate named function? The only time I'll create a named function is when it needs to be explicitly called from more than one place.

Rather, put the code directly in the listener.

So your function has a number of problems. First, "this" is no longer the target element. Another problem is your use of this selector "td > input:checkbox" which selects all input checkboxes that are direct children of <td> elements. Any this-ness is not accounted for (even if this pointed to the right thing).

Is that enough of a clue to loosen things up?

Hint: the parent() or parents() methods may prove helpful.

Also remember that you can limit a selector expression to a subtree of the DOM by passing the subtree root as the second parameter to $().

[ June 11, 2008: Message edited by: Bear Bibeault ]


Hmm I see what you mean with the function problem. So I am going to take your advice and ditch it.

Now I am not sure how parent() or parents() is going help me.

Right now I got your what you said I should try and that is $("#myTable tr).click(function){//event stuff });

So that gets me all the table row in this table.

Now I need to go into the table row and get the the checkbox of each. So would that not be a sibling/child instead?

so I was playing around with something like this.

$(this).siblings("input:checkbox").attr("checked")

This does not work.
So to me this is saying. if anything in this(referring to the tr tag) is a sibling and has a input box of a checkbox that has been check.

Of course this would be in a if statement and it would do stuff and this makes a problem of that any one in that row can set it off. So I probably have to use something with :first or something like that.



But it is not working.


Also remember that you can limit a selector expression to a subtree of the DOM by passing the subtree root as the second parameter to $().


I am not sure what you mean by this.


Thanks

I tried some more thing and this is what I got so far.

if ($(this).siblings("td").siblings(":checkbox:checked"))
{
$(this, "td > input:checkbox").addClass("test");
}

so I have this now. It gets into the loop and does this. The addClass is just in there so I can see if something work it just changes the background color to yellow.

I don't understand why .siblings(":checkbox"checked") works and .siblings(":checkbox").attr("checked",true) does not.
[ June 12, 2008: Message edited by: Michael Hubele ]
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

$(this).siblings("input:checkbox").attr("checked")

This does not work.
So to me this is saying. if anything in this(referring to the tr tag) is a sibling and has a input box of a checkbox that has been check.

First, be sure that you know what "this" is referring to. Is it the <tr> or the <input>? If the <tr>, then siblings() isn't the correct call, right? But let's a assume that siblings() is correct. Then, the statement:
will return a wrapped set of all siblings that match "input:checkbox". But then you add .attr("checked") which returns the value of the "checked" attribute for the first matched element. Not exactly what you meant, I think.

Rather, what I think you wanted was:
Which will return all the sibling checkboxes that are in checked state.
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Originally posted by Bear Bibeault:

First, be sure that you know what "this" is referring to. Is it the <tr> or the <input>? If the <tr>, then siblings() isn't the correct call, right? But let's a assume that siblings() is correct. Then, the statement:
will return a wrapped set of all siblings that match "input:checkbox". But then you add .attr("checked") which returns the value of the "checked" attribute for the first matched element. Not exactly what you meant, I think.

Rather, what I think you wanted was:
Which will return all the sibling checkboxes that are in checked state.


Well I think "this" is referring to the table row. I did alert box and printed the this keyword out in there and it came about with the tableRow obj.


will return a wrapped set of all siblings that match "input:checkbox". But then you add .attr("checked") which returns the value of the "checked" attribute for the first matched element. Not exactly what you meant, I think.



Why does it only do the first matched element and not to all?

**Edit - Never mind with the above statment I think I understand why. For some reason I thought you use the .attr to compare. Like if you did .attr("checked",true). It would look if the incoming object was checked. But upon further reading it seems that it would actually set the attribute to true.

So this: $(this).siblings("td").siblings("input:checkbox:checked")

But this will cause another problem. If You click say the last checkbox in the the row. This will be treated as if it where the checkbox that selected the entire row. So every checkbox will the checkbox that selects the entire row.

So that needs to be limited somehow.
[ June 12, 2008: Message edited by: Michael Hubele ]
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

Only apply the handler to the first checkbox.
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Originally posted by Bear Bibeault:
Only apply the handler to the first checkbox.


Ok

So I did this.

$("td.selectEntireRow").click(function() { ... } );

- selectEntireRow is a css class

So I got lucky and that I am actually planning to use some css styles on that cell. However what happens if I did not have any plans to use css styles? Like could I still use a css class? would that be good practice?

Otherwise each row would have to have its own ID. Since you can't have them all the same ID. Well maybe you can but I am pretty sure that is bad practice.

So in the function part I tried to do this.

if ($(this).siblings("input:checkbox:checked"))
{
$(this + " > input:checkbox").attr("checked", true);
}

I thought this would work. But it does not. Like the if part works good.
But the statement in the if statement does not work. Can you not concatenate like that.

I would have though the statement would replace this with td.selectEntireRow. Then the statement would read All direct children of td.selectEntireRow that are check boxes change their attribute to true.
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

Originally posted by Michael Hubele:
However what happens if I did not have any plans to use css styles? Like could I still use a css class? would that be good practice?
Absolutely. I do it all the time.

I'm not sure what you are trying to do with this:

$(this + " > input:checkbox").attr("checked", true);


But yeah, whatever it was, this won't do it!

Are you trying to limit the selector to descendants of this? If so:

Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182
Originally posted by Bear Bibeault:


But yeah, whatever it was, this won't do it!

Are you trying to limit the selector to descendants of this? If so:



Ya what I am trying to do is this:

Say I got this.



so basically that is one row. Now imagine another 10 rows added with that same format.

So now I am trying to get each of the select row ones to select the reaming row.

So I thought I could have used the "this" keyword to get the current One being selected. then find the decedent checkboxes that belong to it.

So right now I am trying to get it so when you click the any of the select row checkbox that row will be checked(and no other row unless they check other ones).


$('input:checkbox', this)


I don't get this what this is doing. I thought when you do that that is like doing and OR statement.

Still does not check any of the checkboxes in that row.


$("td.selectEntireRow").click(function()
{

if ($(this).siblings("input:checkbox:checked"))
{
$('input:checkbox', this).attr("checked",true)
}
});



Also is their a simple way I can print out what has been selected by this statements.

Like I really with I could print out all the matches say this get me.

$(this).siblings("input:checkbox:checked")

Since this is a big problem I can't visualize what I am selecting.
[ June 12, 2008: Message edited by: Michael Hubele ]
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

Originally posted by Michael Hubele:
So now I am trying to get each of the select row ones to select the reaming[sic] row.

Given your structure, here's how I'd do it:


$('input:checkbox', this)
I don't get this what this is doing. I thought when you do that that is like doing and OR statement.
No. The second parameter defines a subtree of the DOM that will constrain the selection.

Also is their a simple way I can print out what has been selected by this statements.
Firebug in Firefox will let you put statements like:

to show what's what. It's also really useful to see what's been matched by a jQuery selector.

Trying to debug JavaScript without Firebug is like trying to cut diamonds wearing boxing gloves.
[ June 12, 2008: Message edited by: Bear Bibeault ]
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182

$('tr td:first-child :checkbox').click(function(){
if ($(this).attr('checked'))
$(":checkbox",$(this).parents('tr')).attr('checked',true);
});


Ok I don't get a couple thins with this.

But first this

$('input:checkbox', this)

No. The second parameter defines a subtree of the DOM that will constrain the selection.


Ok So when you say this definds a subtree of Dom what do you mean this. Does this mean it takes the first paramter and filters that out. Then takes the second parameter and filter out on the previous sections results?

In your book you have:


But first, let�s examine a simple situation. Let�s say that we want to match all
<img> elements that have either an alt or a title attribute. The powerful jQuery
selectors allow us to express this as a single selector, such as
$('img[alt],img[title]')


So does this mean it can been also used as a or statement?


$('tr td:first-child :checkbox').click(function(){
if ($(this).attr('checked'))
$(":checkbox",$(this).parents('tr')).attr('checked',true);
});


There is a couple things I don't get.

Mainly with this

$(":checkbox",$(this).parents('tr')).attr('checked',true)

Could explain whats going on here. I am not seeing how this works.

Since if we had this:



and we applied your statment: $(":checkbox",$(this).parents('tr')).attr('checked',true)

To me this is what would be happening

See if this was the otherway around(what does not work). and it looked like this:

$( $(this).parents('tr'),":checkbox").attr('checked', true);

it would make more sense to me. Since to me this would go Whatever the incoming checkbox(so say ctl04) find that parents "tr" tag. Then find all "checkboxes" in that select of "tr" and check it.

But like I said I tried to flip it around and it did not work.

So my thinking is wrong for this.



Trying to debug JavaScript without Firebug is like trying to cut diamonds wearing boxing gloves.


Yes I got to learn how to use Firebug I am having a very tough time figuring out what is going on.

Any good firebug jquery/javascript debugging tutorials?

Thanks
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

Ah I see your point of confusion:

that I posted, and the example you took from the book:are completely different things.

Note that in the first example, the comma is outside the selector. The "this" is the second argument to the $() function.

In the second example (from the book), there is only one argument to $() which just happens to contain a selector that uses the CSS comma operator. The two commas have completely different meanings!
Ok So when you say this definds a subtree of Dom what do you mean this.
When you pass a second parameter to the $() function, it specifies the root of the DOM tree that will be searched. By default (when no such argument is passed), the topmost element of the DOM is used. Passing such an argument allows us to limit the part of the DOM tree that is searched for matches.
$(":checkbox",$(this).parents('tr')).attr('checked',true)

Could explain whats going on here. I am not seeing how this works.


OK, the selector is ":checkbox". That will search for all inputs of type checkbox. However, we don;t want all the checkboxes on the page, just the ones in the same table row. So I pass $(this).parents('tr') as the 2nd parameter (as described above) to limit the search to the DOM tree starting at the parent <tr> of the clicked checkbox (whic is what "this" is referencing).

Then I apply .attr('checked',true) to check all the selected checkboxes on the row.

$( $(this).parents('tr'),":checkbox").attr('checked', true);

it would make more sense to me.


Does it make sense now? Since the 2nd param is the DOM tree to search, it doesn't make sense to pass a filter like ":checkbox".
Michael Hubele
Ranch Hand

Joined: Dec 17, 2005
Posts: 182

OK, the selector is ":checkbox". That will search for all inputs of type checkbox. However, we don;t want all the checkboxes on the page, just the ones in the same table row. So I pass $(this).parents('tr') as the 2nd parameter (as described above) to limit the search to the DOM tree starting at the parent <tr> of the clicked checkbox (whic is what "this" is referencing).

Then I apply .attr('checked',true) to check all the selected checkboxes on the row.


would it be wrong to think of it this way?

First it finds the parent "tr" of the incoming(this). What is this case a checkbox. Then it finds all checkboxes in that row and checks them

Thats why I was saying it make more sense to me if it was switched(when I did not know that the 2nd parameter is th DOM filtering). Since the way it seems to search is first gets the DOM filtering and then does the first parameter after.
Bear Bibeault
Author and ninkuma
Marshal

Joined: Jan 10, 2002
Posts: 61654
    
  67

Sure, it's fine to think of it that way, as long as it doesn't prevent you from coming up with the right selector. Remember that the filter selectors (those that start with ':') are applied to filter a base set. So the base set comes first, followed by the filter. And any DOM subtree is passed as the second parameter (not part of the selector).
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Need Help with binding click events to table rows