Jason Schilling
Jason Schilling

Reputation: 476

jQuery selecting direct "parents", not similar

I got a fixed structure of a table like this one:

<table>
    <tr><td class="lvl-0">1</td><tr>
    <tr><td class="lvl-1">2</td><tr>
    <tr><td class="lvl-2">3</td><tr>
    <tr><td class="lvl-2">4</td><tr>
    <tr><td class="lvl-2">5</td><tr>
    <tr><td class="lvl-1">6</td><tr>
    <tr><td class="lvl-2">7</td><tr>
    <tr><td class="lvl-2 selected">8</td><tr>
    <tr><td class="lvl-2">9</td><tr>
</table>

I want to select every lvl parent. That means I want to select every lvl previously from the selected. Except similar. That means in this example it would be 6 and 1

I tried it with this:

var ss = [];
for(var l = lvl; l <= 5; l++){
    ss.push('td.lvl-'+l);
}
var ul = jQuery('table').find(ss.join(',')).closest('tr');
var pa = jQuery('.selected').closest('tr').prevAll('tr').not(ul);

But it also select number 2

// EDIT

I have a jsfiddle http://jsfiddle.net/g7yhwojg/3/ selected should be:

Upvotes: 3

Views: 101

Answers (2)

David Thomas
David Thomas

Reputation: 253318

While you've already posted your own answer, I thought I'd offer an alternative, in case you're interested:

// caching the selected element (selecting by its id):
var selected = $('#selected'),

// caching the regular expression, in case it might be
// be needed again later; this matches a serious of
// one or more (+) numbers (\d) at the end of the
// string ($):
    levelRegex = /\d+$/,

// finding the numbers at the end of the selected
// element's class attribute, and using parseInt()
// to convert that to a number in base-10:
    selectedLevel = parseInt(selected.attr('class').match(levelRegex), 10),

// caching the selected element's closest ancestor
// <tr> element:
    selectedParent = selected.closest('tr'),

// caching the <tr> elements before the selectedParent:
    rowsBefore = selectedParent.prevAll(),

// using map() to iterate over those elements and
// if their child <td> element has a class equal to
// 'lvl-' + (selectedLevel - 1)
// we first decrement selectedLevel, and then
// return the text of the current <tr> element;
// decrementing here means we can only ever
// retrieve the first instance of an element
// with a 'lower' level:
    pseudoParents = rowsBefore.map(function (i) {
        if ($(this).find('td').hasClass('lvl-' + (selectedLevel - 1))) {
            --selectedLevel;
            return this.textContent;
        }

// converting the 'map' into a native Array:
    }).get();

console.log(pseudoParents);
// ["14", "13", "10", "1"]

var selected = $('#selected'),
  levelRegex = /\d+$/,
  selectedLevel = parseInt(selected.attr('class').match(levelRegex), 10),
  selectedParent = selected.closest('tr'),
  rowsBefore = selectedParent.prevAll(),
  pseudoParents = rowsBefore.map(function(i) {
    if ($(this).find('td').hasClass('lvl-' + (selectedLevel - 1))) {
      --selectedLevel;
      return this.textContent.trim();
    }
  }).get();

// snippet logs to the bottom of the result panel:
snippet.log(pseudoParents);

// logs to the console (obviously):
console.log(pseudoParents);
// ["14", "13", "10", "1"]
.lvl-0 {
  padding-left: 10px;
}
.lvl-1 {
  padding-left: 30px;
}
.lvl-2 {
  padding-left: 50px;
}
.lvl-3 {
  padding-left: 70px;
}
.lvl-4 {
  padding-left: 90px;
}
.lvl-5 {
  padding-left: 110px;
}
body {
  color: #ffffff;
  background: #000000;
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <tr>
    <td class="lvl-0">1</td>
  </tr>
  <tr>
    <td class="lvl-1">2</td>
  </tr>
  <tr>
    <td class="lvl-2">3</td>
  </tr>
  <tr>
    <td class="lvl-2">4</td>
  </tr>
  <tr>
    <td class="lvl-2">5</td>
  </tr>
  <tr>
    <td class="lvl-1">6</td>
  </tr>
  <tr>
    <td class="lvl-2">7</td>
  </tr>
  <tr>
    <td class="lvl-2">8</td>
  </tr>
  <tr>
    <td class="lvl-2">9</td>
  </tr>
  <tr>
    <td class="lvl-1">10</td>
  </tr>
  <tr>
    <td class="lvl-2">11</td>
  </tr>
  <tr>
    <td class="lvl-2">12</td>
  </tr>
  <tr>
    <td class="lvl-2">13</td>
  </tr>
  <tr>
    <td class="lvl-3">14</td>
  </tr>
  <tr>
    <td class="lvl-4">15</td>
  </tr>
  <tr>
    <td class="lvl-4" id="selected">16</td>
  </tr>
  <tr>
    <td class="lvl-3">17</td>
  </tr>
  <tr>
    <td class="lvl-1">18</td>
  </tr>
  <tr>
    <td class="lvl-2">19</td>
  </tr>
  <tr>
    <td class="lvl-2">20</td>
  </tr>
  <tr>
    <td class="lvl-2">21</td>
  </tr>
</table>

External JS Fiddle demo, for experimentation and development.

Note that in both the Stack Snippet, and the JS Fiddle, I've corrected the HTML to close the <tr> elements, otherwise the erroneous <tr> tags at the end of each line of the <table> was creating a new, empty, <tr> for no reason.

References:

Upvotes: 1

Jason Schilling
Jason Schilling

Reputation: 476

I got it on my own.

var lvls = [];
pa = pa.filter(function(){
    var pc = jQuery(this).find('td').attr('class');
    if(lvls.indexOf(pc) == -1){
        console.log(pc);
        lvls.push(pc);
        return true;
    }
    return false;
});

http://jsfiddle.net/g7yhwojg/11/

I looped through all the upper elemnts and took everytime only the first.

Upvotes: 5

Related Questions