Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

select child element jQuery

I have a table structured like this:

<table>
  <tbody>
  for loop here
    <tr>
      <td>Item X Attribute 1</td>
      <td>Item X Attribute 2</td>
      <td><button name="test" onclick="display_variants()">Hide my kids</button></td>
    </tr>
    <tr>
      <tbody class="variants_info">
        <tr>
          <td>Item X Variant 1</td>
          <td>Item X Variant 2</td>
        </tr>
      </tbody>
    </tr>
endfor loop
  </tbody>
</table>

So that structure repeats Y amount of times.

I'm trying to make a script that hides the tbody.variants of the row selected.

What I have so far is this:

<script>
  function display_variant(){
    if($('.variants_info').is(":visible")){
        $('.variants_info').hide();
    }
    else{
        $('.variants_info').show();
    }
  }
</script>

but this hides the variants from ALL the rows.

Is there a way to select the childs of the specific row? Also how can I start with the tbody.variants hidden? (Start as in when I visit the page).

Edit: At the moment is looking closely to this: enter image description here

Update: I've managed to change the structure to this:

<table>
  for loop
    <tbody>
      <tr>
        <td>image for el 1</td>
        <td>attr for el 1</td>
        <td><button type='button' name='test'>Click Me</button></td>
      </tr>
      for loop
        <tr class='variants_info'>
          <td>variant1 for el 1</td>
          <td>variant2 for el 1</td>
        </tr>
      endfor
    </tbody>
  endfor
</table>

Update 2: The actual code is this one:

<table class="pure-table pure-table-bordered">
  <tbody>
  {% for product in collection.products %}
  {% if product.available %}

    <tr class="{% cycle 'pure-table-odd', '' %}">
      <td>
        <img src="{{ product.featured_image.src | product_img_url: 'thumb' }}" alt="{{ product.featured_image.alt | escape }}" />
      </td>
      <td>{{ product.title }}</td>
      <td style="text-align:right">
        <button type="button" name="click_me">Click Me</button>
      </td>
      </tr>
      {% for variant in product.variants %}
    <tr>
      <td>{{variant.title}}</td>
      <td>{{variant.price | money }}</td>
    </tr>
    {% endfor %}       
        {% endif %}
        {% endfor %}
    </tbody>
</table>

<script>
  $("td button").click(function(){
    $(this).closest('tr').next().toggle();
  })
</script>

I still can't get the JS to work.. =/ Current one is only hiding the first variant( Instead of all the variants for the clicked button )

like image 304
Onilol Avatar asked Apr 29 '16 20:04

Onilol


People also ask

How do you get the children of the $( this selector?

Answer: Use the jQuery find() Method You can use the find() method to get the children of the $(this) selector using jQuery. The jQuery code in the following example will simply select the child <img> element and apply some CSS style on it on click of the parent <div> element.

How do you get children of children in jQuery?

The children() method returns all direct children of the selected element. The DOM tree: This method only traverse a single level down the DOM tree. To traverse down multiple levels (to return grandchildren or other descendants), use the find() method.

What is a parent child selector?

The ("parent > child") selector selects all elements that are a direct child of the specified element.

How can I get grandchild in jQuery?

I can use $('#root > * > *') to get all its grandchildren.


3 Answers

I would suggest to mark the rows that contain the products with a class name, e.g. "product", like this:

<tr class="product {% cycle 'pure-table-odd', '' %}">
  <td>
    <img src="{{ product.featured_image.src | product_img_url: 'thumb' }}" 
         alt="{{ product.featured_image.alt | escape }}" />
  </td>
  <td>{{ product.title }}</td>
  <td style="text-align:right">
    <button type="button" name="click_me">Click Me</button>
  </td>
</tr>

You would not add that class to the rows that have the variants.

Then in your JavaScript use the nextUntil method to match all next variant rows (which do not have the "product" class) until, but excluding, the next product row, and apply the toggle() method to all these:

$("td button").click(function(){
    $(this).closest('tr').nextUntil('.product').toggle();
});

Alternative structure 1

Instead of a single table, you could create nested tables, one for each product, containing the variants. It would look somewhat like this:

<table class="pure-table pure-table-bordered">
  <tbody>
  {% for product in collection.products %}
  {% if product.available %}

    <tr class="{% cycle 'pure-table-odd', '' %}">
      <td>
        <img src="{{ product.featured_image.src | product_img_url: 'thumb' }}" 
             alt="{{ product.featured_image.alt | escape }}" />
      </td>
      <td>{{ product.title }}</td>
      <td style="text-align:right">
        <button type="button" name="click_me">Click Me</button>
      </td>
    </tr>
    <tr>
        <table class="some other class specific for variants">
          <tbody> 
            {% for variant in product.variants %}
            <tr>
              <td>{{variant.title}}</td>
              <td>{{variant.price | money }}</td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
    </tr>
  {% endif %}
  {% endfor %}
  </tbody>
</table>

This has advantages and disadvantages. The main disadvantage is that the columns of these sub-tables are not aligned with the columns in the main table. But it depends on what you want...

The JavaScript code would then have to be like you had it originally:

$("td button").click(function(){
    $(this).closest('tr').next().toggle();
});

Alternative structure 2

You could also wrap each "section" (consisting of one product row and the variant rows that belong to it) with a tbody tag. Although not commonly done, this is allowed as stated on MDN:

Note that unlike the <thead>, <tfoot>, and <caption> elements however, multiple <tbody> elements are permitted (if consecutive), allowing the data-rows in long tables to be divided into different sections, each separately formatted as needed.

This is different from your original HTML, where you had tbody elements as children of tr elements, which is invalid HTML.

It would look like this:

<table class="pure-table pure-table-bordered">
  {% for product in collection.products %}
  {% if product.available %}

  <tbody>
    <tr class="{% cycle 'pure-table-odd', '' %}">
      <td>
        <img src="{{ product.featured_image.src | product_img_url: 'thumb' }}" 
             alt="{{ product.featured_image.alt | escape }}" />
      </td>
      <td>{{ product.title }}</td>
      <td style="text-align:right">
        <button type="button" name="click_me">Click Me</button>
      </td>
    </tr>
    {% for variant in product.variants %}
    <tr>
      <td>{{variant.title}}</td>
      <td>{{variant.price | money }}</td>
    </tr>
    {% endfor %}
  </tbody>
  {% endif %}
  {% endfor %}
</table>

You can then use the nextAll() method to hide the variant rows, because they are delimited by the tbody wrapper from the next product row:

$("td button").click(function(){
    $(this).closest('tr').nextAll().toggle();
});

Initially hiding the variant rows

If you want the variants all to be hidden at first, then add the following attribute to those rows in the HTML code:

<tr style="display:hidden">

You would of course not do this for the product rows. Also, you might want to define a CSS class for this (e.g. tr.hidden { display:hidden; } instead of using style.

The jQuery toggle() method will override this style when showing, and restore it again when hiding.

like image 102
trincot Avatar answered Oct 21 '22 07:10

trincot


Your HTML is not valid so you can change that and then use this DEMO

$("td button").click(function() {
  $(this).closest('tr').next().toggle();
})
like image 23
Nenad Vracar Avatar answered Oct 21 '22 06:10

Nenad Vracar


try this one :-

$("td button").click(function() {
  $(this).closest('tr').nextUntil("tbody").toggle();
});

the jsfiddle demo link is :- https://jsfiddle.net/Lg0wyt9u/776/

like image 32
Pawan Kashyap Avatar answered Oct 21 '22 06:10

Pawan Kashyap