views:

2290

answers:

4

In the example below:

<html>
<head>
<script src="some.js" type="text/javascript"></script>
<script type="text/javascript">

//???
//???

);

</script>
</head>
<body>
<table>
<tr id="parent_1">
<td>Parent 1</td>
</tr>
<tr class="child">
<td>Child 1</td>
</tr>
<tr class="child">
<td>Child 2</td>
</tr>
<tr id="parent_2">
<td>Parent2</td>
</tr>
</table>
</body>
</html>

I wanted "Parent 1" text to change to "Parent 1(2)" where '2' is the number of childs for the given parent using Java script or Jquery. How is this possible?

I'm new to JQuery and Java script.

Please let me know.

+7  A: 

Mmm. Tough one. :) This should do it, though:

$(function() {
    $("tr[id^='parent_']").each(function() {
        var count = 0;
        $(this).nextAll('tr').each(function() {
            if($(this).hasClass('child')) {
                count++;
            } else {
                return false;
            }
        });
        $(this).find('td').append(' (' + count + ')');
    });
});

Tested and works.


Although the above works, it is not very efficient. I also want to take a second to suggest you change the format of your HTML a little bit. You want to make your code be as semantically relevant to the content it holds as possible. Having one huge table mixing parents and childs is not the optimal way of achieving this. I am not sure what your use case is here, but consider doing something like this:

<ul>
  <li id="parent_1">
    <span>Parent 1</span>
    <ul>
      <li>Children 1</li> 
      <li>Children 2</li>
      <li>Children 3</li>
    </ul>
  </li>
  <li id="parent_2">
    <span>Parent 2</span>
    <ul>
      <li>Children 1</li> 
    </ul>
  </li>
  <li id="parent_3">
    <span>Parent 3</span>
    <ul>
      <li>Children 1</li> 
      <li>Children 2</li>
    </ul>
  </li>
</ul>

You could still style this however you want to give it the appearance you want, although it may not be as easy if you really are displaying tabular data about the parents and children.

With that code, however, you could then simplify the above with a much more efficient:

$('ul > li').each(function() {
    var count = $(this).find('li').length;
    $('span', this).append(' (' + count + ')');
});

If changing the code from a table to a list is not possible/desired, but you have access to the server-side code that presumably generates this table, you could at least make things easier then by giving all the children a class with the ID of the parent, and giving all the parents a common class:

<table>
    <tr id="parent_1" class="parent">
        <td>Parent 1</td>
    </tr>
    <tr class="child parent-1">
        <td>Child 1</td>
    </tr>
    <tr class="child parent-1">
        <td>Child 2</td>
    </tr>
    <tr id="parent_2" class="parent">
        <td>Parent2</td>
    </tr>
    <tr class="child parent-2">
        <td>Child 1</td>
    </tr>
    <tr id="parent_3" class="parent">
        <td>Parent3</td>
    </tr>
    <tr class="child parent-3">
        <td>Child 1</td>
    </tr>
    <tr class="child parent-3">
        <td>Child 2</td>
    </tr>
    <tr class="child parent-3">
        <td>Child 3</td>
    </tr>
</table>

Which would then allow you to do this, much faster than the original solution:

$('tr.parent').each(function() {
    var id = $(this).attr('id').split('_').pop();
    var count = $('tr.parent-' + id).length;
    $(this).find('td').append(' (' + count + ')');
});
Paolo Bergantino
+1 for solving it and then suggesting a more appropriate layout to fit the needs.
Jab
+1  A: 

Give the parents a class of "parent" to make it a bit easier.

$('tr.parent').each(function() {
  var next = $(this).next();
  var count = 1;
  while (next = $(next).next() && $(next).hasClass('child')) {
    count++;
  }
  $(this).find('td').append(' (' + count + ')');
});
Matt
This doesn't work with the HTML pasted above.
Paolo Bergantino
A: 

Because your html doesn't actually place the child nodes below the parent nodes in markup, the easiest way to do this will be to loop through all the TR's and count up class="child" for each parent. Paolo's code should do this for you.

Better would be to have the child nodes defined as actually children of the parent td, then jquery can simplify things for you. If you can afford to refactor your table like this:

<table>
<tr id="parent_1">
<td>Parent 1
<table>
<tr class="child">
<td>Child 1</td>
</tr>
<tr class="child">
<td>Child 2</td>
</tr>
</table>
</td>
</tr>
<tr id="parent_2">
<td>Parent2</td>
</tr>
</table>

then you can write simpler jquery like:

$("td").each(function(){$(this).val($(this).val() + "(" + $(this).find("td").length + ")"); });
Joel Potter
A: 

I'm finding the complex jQuery selectors and loops quite amusing, given that the DOM already has a perfectly good ‘rowIndex’ property you can use to grab the number of children simply and much more efficiently:

var p1= document.getElementById('parent_1');
var p2= document.getElementById('parent_2');

var childn= p2.rowIndex-p1.rowIndex-1;
p1.cells[0].firstChild.data+= ' ('+childn+')';
bobince
If you're going to smugly point out something we all missed, at least provide working code that will work for any set of parents. :) I would imagine getting the next parent, determining the count if it's the last parent, etc, would get worse than most of the solutions provided.
Paolo Bergantino