Jan Veen
Jan Veen

Reputation: 33

JQuery/javascript selectors and html table manipulation

Somehow I just get stuck getting this to work. I have a table in which I exchange rows with two buttons for up and down. This works, but I have to exclude 1 column from that operation. What is going wrong here? As I have the selectors now, nothing is coming up, neither for the row which is moved nor the row which makes place, both up and down. What is the best way to shape the selectors or is there any other way to make this happen?At this moment a have this code:

<!DOCTYPE html>

<html>
<head>
    <title>energiesale test</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="scripts/jquery-1.11.1.min.js"></script>

</head>
<body>

    <table>
        <thead><tr>
<th>header1</th><th>header2</th><th>header3</th><th>header 4</th>   </tr></thead> 
        <tbody><tr class='row'><td>rij 1</td><td>cell 1</td><td class='id'>1</td><td><button value='up' class="up">Up</button> <button value='down' class="down">Down</button></td></tr>
            <tr class='row'><td>rij 2</td><td>cell 2</td><td class='id'>2</td><td><button value='up' class="up">Up</button> <button value='down' class="down">Down</button></td></tr>
        <tr class='row'><td>rij 3</td><td>cell 3</td><td class='id'>3</td><td><button value='up' class="up">Up</button> <button value='down' class='down'>Down</button></td></tr>
        <tr class='row'><td>rij 4</td><td>cell 4</td><td class='id'>4</td><td><button value='up' class="up">Up</button> <button value='down' class='down'>Down</button></td></tr>
        </tbody>
    </table>
      <script type="text/javascript">
$(document).ready(function(){
    $('.up').on('click',function() {
        var parent = $(this).parents(".row");
        var parent_id = $(this).parents(".row:first").find('.id').val();
        var prev_id = parent.prev('.row:first').find('.id').val();
        parent.insertBefore(parent.prev(".row"));
        $(this).parents(".row").find('.id').val(prev_id);
        parent.prev('.row:first').find('.id').val(parent_id);
    });
    $('.down').on('click',function(){
        var parent = $(this).parents(".row");
         var parent_id = $(this).parents(".row").find('.id').val();
        var next_id = parent.next('.row').find('.id').val();
        parent.insertAfter(parent.next(".row"));
        $(this).parents('.row').find('.id').val(next_id);
        parent.prev('.row').find('.id').val(parent_id);
    })
    ;
 })


</script> 
</body>
</html>

Upvotes: 3

Views: 233

Answers (4)

Dimitri Zetzsche
Dimitri Zetzsche

Reputation: 187

Working example: http://jsfiddle.net/H72Ye/2/

I think I see what you are trying to do: the header 4 column may not shift right?

You are using .val() to fetch the value of the <td> with class="id". This will not work. You example doesn't work because parent_id and next_id are empty when you fetch them.

JQuery documentation says (http://api.jquery.com/val/):

The .val() method is primarily used to get the values of form elements such as input, select and textarea.

You want to set the HTML content of a element, http://api.jquery.com/html/:

In an HTML document, .html() can be used to get the contents of any element.

You must use .html() instead:

var parent_id =  $(this).parents(".row").find('.id').html();
var next_id = parent.next('.row').find('.id').html();

PS: there is still something wrong with you 'UP'-function. you need that to debug properly.

i've solved this. I've changed the following in $('.up').on('click',function() {}):

parent.prev('.row:first').find('.id').html(parent_id);

to

parent.next('.row:first').find('.id').html(parent_id);

EDIT: I also added some additional IF-clauses to fix some bugs. Updated JSFiddle: http://jsfiddle.net/H72Ye/6/

Upvotes: 2

jme11
jme11

Reputation: 17397

Similar to the other solution, but a bit less verbose. You don't need to check the length of the previous/next row since you already have a variable for prev_id/next_id. These will be empty if there was no row.

$('.up').on('click', function () {
    var parent = $(this).parents('tr');
    var parent_id = parent.find('.id').text();
    var prev_id = parent.prev().find('.id').text();
    if (prev_id.length) {
        parent.insertBefore(parent.prev());
        parent.find('.id').text(prev_id);
        parent.next().find('.id').text(parent_id);
    }
});
$('.down').on('click', function () {
    var parent = $(this).parents('tr');
    var parent_id = parent.find('.id').text();
    var next_id = parent.next().find('.id').text();
    if (next_id.length) {
        parent.insertAfter(parent.next());
        parent.find('.id').text(next_id);
        parent.prev().find('.id').text(parent_id);
    }
});

Upvotes: 1

RobG
RobG

Reputation: 147453

A plain JS solution, there are a couple of helpers. It's pretty simple if you don't have to keep the cells in place.

function moveUp() {
  var el = this;
  var row0 = getAncestor(el, 'tr');
  var row1 = row0 && getPreviousElementSibling(row0);

  // If no row or is top row, can't move up
  if (!row0 || !row1) return;

  // Swap rows
  row0.parentNode.insertBefore(row0, row1);

  // Put td back
  var cell0 = row0.querySelector('.id');
  var cell1 = row1.querySelector('.id');

  if (cell0 && cell1) {
    var t = cell0.cloneNode(false);
    row0.replaceChild(t, cell0);
    row1.replaceChild(cell0, cell1);
    row0.replaceChild(cell1, t);
  }
}

moveDown is almost identical, perhaps it should be one function with a direction parameter.

function moveDown() {
  var el = this;
  var row0 = getAncestor(el, 'tr');
  var row1 = row0 && getNextElementSibling(row0);

  // If no row or is bottom row, can't move down
  if (!row0 || !row1) return;

  var section = row0.parentNode;

  // Swap rows
  section.insertBefore(row1, row0);

  // Put td back
  var cell0 = row0.querySelector('.id');
  var cell1 = row1.querySelector('.id');

  if (cell0 && cell1) {
    var t = cell0.cloneNode(false);  // use clone as a placeholder
    row0.replaceChild(t, cell0);     // put t where 0 is
    row1.replaceChild(cell0, cell1); // put 0 where 1 is
    row0.replaceChild(cell1, t);     // put 1 where t is and 0 was
  }
}

Helpers

// Get ancestor with tagName
// Return element or undefined
function getAncestor(el, tagName) {
  tagName = tagName.toLowerCase();
  do {
    el = el.parentNode;
    if (el.tagName.toLowerCase() == tagName) {
      return el;
    }
  } while (el.parentNode)
}

// Get previous element sibling, ignore #text nodes
function getPreviousElementSibling(el) {
  do {
    el = el.previousSibling;
  } while (el && el.nodeType != 1)
  return el;
}

// Get next element sibling, ignore #text nodes
function getNextElementSibling(el) {
  do {
    el = el.nextSibling;
  } while (el && el.nodeType != 1)
  return el;
}

Simple function to add the listeners

function addListeners() {
  var ups = document.querySelectorAll('.up');
  for (var i=0, iLen=ups.length; i<iLen; i++) {
    ups[i].onclick = moveUp;
  }
  var downs = document.querySelectorAll('.down');
  for (var j=0, jLen=ups.length; j<jLen; j++) {
    downs[j].onclick = moveDown;
  }
}

window.onload = addListeners;

Upvotes: 1

Shaunak D
Shaunak D

Reputation: 20636

Working Demo

  1. .val() is a function used to get values of input elements. You should use .text() instead.

  2. Getting prev_id, check whether it has previous element. Same for next_id


$(document).ready(function () {
    $('.up').on('click', function () {
        var parent = $(this).parents(".row");
        var parent_id = $(this).parents(".row:first").find('.id').text();
        if (parent.prev().length) {
            var prev_id = !parent.prev().length ? parent_id : parent.prev('.row:first').find('.id').text();
            parent.insertBefore(parent.prev(".row"));
            parent.find('.id').text(prev_id);
            parent.next().find('.id').text(parent_id);
        }
    });
    $('.down').on('click', function () {
        var parent = $(this).parents(".row");
        var parent_id = $(this).parents(".row").find('.id').text();
        if (parent.next().length) {
            var next_id = !parent.next().length ? parent_id : parent.next('.row').find('.id').text();
            parent.insertAfter(parent.next(".row"));
            parent.find('.id').text(next_id);
            parent.prev().find('.id').text(parent_id);
        }
    });
})

Upvotes: 2

Related Questions