user173420
user173420

Reputation: 376

How can I move a list item to first position and then back?

I'm trying to adapt this code to my li lists. [enter image description here I sketched something that shows the exact logic.

This is the code:

$('ul li').each(function() {

    var $this = $(this).data({
            position: $(this).index()
        }),
        $table = $this.closest('ul'),
        $input = $this.find('input');

    $input.bind('click', function(e) {
        var $first = $table.find('li:first'),
            position;

        if ($(this).is(':checked')) {
            position = $first.data('position');
            $table.find('li input').not($(this)).removeAttr('checked');
            if (position != 0) $first.insertAfter($table.find('li').eq(position));
            $this.prependTo($table);
        } else if ($this.data('position') != 0) {
            position = $this.data('position');
            $this.insertAfter($table.find('li').eq(position));
        }
    });

});

I have the code below that works with tables but I'd like to implement this on a ul li. Is there a way to make the checkbox input becoming a li or a anchor tag?

Demo

Upvotes: 3

Views: 1652

Answers (3)

Shlomi Hassid
Shlomi Hassid

Reputation: 6606

Based on your example I assume you don't have control on the html source and you want to change the table to a list dynamically.

Here is an example (commented) based on your code and original example html.

Pretty straight forward:

//Unique table selector that is targeted to be parsed and replaced:
var $targetTable = $("table"); 
//This is the target new list that will store the list items:
var $sudoul = $("<ul></ul>");
//Toggle through all the rows and create a list item:
$targetTable.find('tr').each(function () {
    
    $sudoul.append($("<li style='border:1px solid black; cursor:pointer'>" + $(this).text() + "</li>")
           //This binds a click event to the new LI stored in $sudoul
           .bind("click", function(){
						
            //if we click the first element avoid and don't to anything:
            if ($(this).is(':first-child')) return;
						
            var $container = $(this).closest("ul");
            var $this      = $(this); // The clicked item to move UP.
            var $first     = $container.find("li").eq(0); // The first list item to be replaced.
            
            //First move the item to the head of the list:
            $container.prepend($this.data("alreadyclicked", true));
            
            //Check if the first element was already moved the append it to the end of the list
            if ($first.data("alreadyclicked")) $container.append($first);

          })
          .data({alreadyclicked: false }) // this flag is set to true when the element is clicked
    );
});
//Replace the table with the newly created list:
$targetTable.replaceWith($sudoul);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<table>
    <tbody>
        
    <tr>
        <td><input type="checkbox" /></td>
        <td>1</td>
    </tr>
    <tr>
        <td><input type="checkbox" /></td>
        <td>3</td>
    </tr>
    <tr>
        <td><input type="checkbox" /></td>
        <td>A</td>
    </tr>
    <tr>
        <td><input type="checkbox" /></td>
        <td>B</td>
    </tr>
    <tr>
        <td><input type="checkbox" /></td>
        <td>C</td>
    </tr>
    
    </tbody>
</table>

Upvotes: 1

Sergio Cabral
Sergio Cabral

Reputation: 6966

If you don't want to use checkbox but use simple tags, see this example:

See in JSFiddler: http://jsfiddle.net/nfywg06b/5/

I have not renamed the variables so that it is easy to understand the important adjustments.

Use the goToLast variable to define the behavior: Send to last position or change position (legacy behavior)

jQuery:

var goToLast = true;

$('.item').each(function() {

  var $this = $(this).data({
      position: $(this).index()
    }),
    $table = $this.closest('.container'),
    $input = $this;

  $input.bind('click', function(e) {
    $input.toggleClass('selected');

    var $first = $table.find('.item:first'),
      position;

    if ($(this).hasClass('selected')) {
      position = !goToLast ? $first.data('position') : $table.children().length - 1;
      $table.find('.item').not($(this)).removeClass('selected');
      if (position != 0) $first.insertAfter($table.find('.item').eq(position));
      $this.prependTo($table);
    } else if ($this.data('position') != 0) {
      position = $this.data('position');
      $this.insertAfter($table.find('.item').eq(position));
    }
  });

});

HTML:

<div class="container">
  <a href="#" class="item">1</a>
  <a href="#" class="item">3</a>
  <a href="#" class="item">A</a>
  <a href="#" class="item">B</a>
  <a href="#" class="item">C</a>
</div>

CSS:

a.item {
  display: block;
  background-color: silver;
  border: 1px solid gray;
  padding: 10px;
  margin: 10px;
}

a.item.selected {
  background-color: green;
}

Upvotes: 1

Sergio Cabral
Sergio Cabral

Reputation: 6966

Making some adjustments in your JSFiddle code is working like this:

See the example here: http://jsfiddle.net/z0bga89t/

See de HTML code above:

<ul>
    <li>
        <input type="checkbox" />
        1
    </li>
    <li>
        <input type="checkbox" />
        3
    </li>
    <li>
        <input type="checkbox" />
        A
    </li>
    <li>
        <input type="checkbox" />
        B
    </li>
    <li>
        <input type="checkbox" />
        C
    </li>
</ul>

And jQuery:

$('li').each(function () {
    var $this  = $(this).data({position: $(this).index()}),
      $table = $this.closest('ul'),
      $input = $this.find('input');

  $input.bind('click', function (e) {
    var $first = $table.find('li:first'),
        position;

    if ($(this).is(':checked')) {
        position = $first.data('position');
        $table.find('li input').not($(this)).removeAttr('checked');
        if (position != 0) $first.insertAfter($table.find('li').eq(position));
        $this.prependTo($table);
    } else if ($this.data('position') != 0) {
        position = $this.data('position');
        $this.insertAfter($table.find('li').eq(position));                
    }
  });
});

Note that just changing the corresponding tags:

  • table to ul
  • tr to li

Upvotes: 1

Related Questions