Sort an html list with javascript - javascript

I have a set of three list items that I would like to automatically display from high to low on page load. Ideally using jquery or javascript.
<ul class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
Each list item needs its own ID because they each have individual background images. The numbers must text nodes so that a user can edit them.

This will probably be the fastest way to do it, since it doesn't use jQuery:
function sortList(ul){
var new_ul = ul.cloneNode(false);
// Add all lis to an array
var lis = [];
for(var i = ul.childNodes.length; i--;){
if(ul.childNodes[i].nodeName === 'LI')
lis.push(ul.childNodes[i]);
}
// Sort the lis in descending order
lis.sort(function(a, b){
return parseInt(b.childNodes[0].data , 10) -
parseInt(a.childNodes[0].data , 10);
});
// Add them into the ul in order
for(var i = 0; i < lis.length; i++)
new_ul.appendChild(lis[i]);
ul.parentNode.replaceChild(new_ul, ul);
}
Call the function like:
sortList(document.getElementsByClassName('list')[0]);
You can sort other lists the same way, and if you have other elements on the same page with the list class you should give your ul an id and pass it in using that instead.
Example JSFiddle
Edit
Since you mentioned that you want it to happen on pageLoad, I'm assuming you want it to happen ASAP after the ul is in the DOM which means you should add the function sortList to the head of your page and use it immediately after your list like this:
<head>
...
<script type="text/javascript">
function sortList(ul){
var new_ul = ul.cloneNode(false);
var lis = [];
for(var i = ul.childNodes.length; i--;){
if(ul.childNodes[i].nodeName === 'LI')
lis.push(ul.childNodes[i]);
}
lis.sort(function(a, b){
return parseInt(b.childNodes[0].data , 10) - parseInt(a.childNodes[0].data , 10);
});
for(var i = 0; i < lis.length; i++)
new_ul.appendChild(lis[i]);
ul.parentNode.replaceChild(new_ul, ul);
}
</script>
</head>
<body>
...
<ul class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
<script type="text/javascript">
!function(){
var uls = document.getElementsByTagName('ul');
sortList( uls[uls.length - 1] );
}();
</script>
...
</body>

You can try this
var ul = $(".list:first");
var arr = $.makeArray(ul.children("li"));
arr.sort(function(a, b) {
var textA = +$(a).text();
var textB = +$(b).text();
if (textA < textB) return -1;
if (textA > textB) return 1;
return 0;
});
ul.empty();
$.each(arr, function() {
ul.append(this);
});
Live example : http://jsfiddle.net/B7hdx/1

you can use this lightweight jquery plugin List.js cause
it's lightweight [only 3K script]
easy to implement in your existing HTML table using class
searchable, sortable and filterable
HTML
<div id="my-list">
<ul class="list">
<li>
<h3 class="name">Luke</h3>
</li>
<li>
<h3 class="name">John</h3>
</li>
</ul>
</div>
Javascript
var options = {
valueNames: ['name']
};
var myList = new List('my-list', options);

There's also this small jQuery plugin. Which would make your sort nothing more than:
$('.list>li').tsort({attr:'id'});

This code will sort that list assuming there is only one .list item:
function sortList(selector) {
var parent$ = $(selector);
parent$.find("li").detach().sort(function(a, b) {
return(Number(a.innerHTML) - Number(b.innerHTML));
}).each(function(index, el) {
parent$.append(el);
});
}
sortList(".list");
You can see it work here: http://jsfiddle.net/jfriend00/FjuMB/
To explain how it works:
It gets the .list parent object.
It finds all the <li> child objects.
It removes all the <li> child objects from the DOM, but preserves their data
It sorts the li objects using a custom sort function
The custom sort function gets the HTML in the li tag and converts it to a number
Then, traversing the array in the newly sorted order, each li tag is appended back onto the original parent.
The result is that they are displayed in sorted order.
Edit:
This improved version will even sort multiple list objects at once:
function sortList(selector) {
$(selector).find("li").sort(function(a, b) {
return(Number(a.innerHTML) - Number(b.innerHTML));
}).each(function(index, el) {
$(el).parent().append(el);
});
}
sortList(".list");
Demo: http://jsfiddle.net/jfriend00/RsLwX/

Non jquery version (vanilla javascript)
Benefits: the list is sorted in place, which doesn't destroy the LI's nor remove any events that may be associated with them. It just shuffles things around
Added an id to the UL:
<ul id="myList" class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
and the vanilla javascript (no jquery)
// Grab a reference to the UL
var container = document.getElementById("myList");
// Gather all the LI's from the container
var contents = container.querySelectorAll("li");
// The querySelector doesn't return a traditional array
// that we can sort, so we'll need to convert the contents
// to a normal array.
var list = [];
for(var i=0; i<contents.length; i++){
list.push(contents[i]);
}
// Sort based on innerHTML (sorts "in place")
list.sort(function(a, b){
var aa = parseInt(a.innerHTML);
var bb = parseInt(b.innerHTML);
return aa < bb ? -1 : (aa > bb ? 1 : 0);
});
// We'll reverse the array because our shuffle runs backwards
list.reverse();
// Shuffle the order based on the order of our list array.
for(var i=0; i<list.length; i++){
console.log(list[i].innerHTML);
container.insertBefore(list[i], container.firstChild);
}
And the fiddle proof: https://jsfiddle.net/L27gpnh6/1/

You can use this method:
var mylist = $('ul');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
var compA = $(a).text().toUpperCase();
var compB = $(b).text().toUpperCase();
return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });
Check the article here:
http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/
Edit: There is a very cool jquery plugin that does that : http://tinysort.sjeiti.com/

Something like this should help:
var $parent = $(".list");
$(".list li").sort(function (a, b) {
return window.parseInt($(a).text(), 10) - window.parseInt($(b).text(), 10);
}).remove().each(function () {
$parent.append($(this));
});

One method could be to sort an array (well, a jQuery object) of the li elements and replace the contents (using the html method) of the ul with the sorted array of elements:
$(".list").html($(".list li").sort(function(a, b) {
return parseInt($(b).text(), 10) - parseInt($(a).text(), 10);
}));
Here's a working example.

using jQuery for help:
var sortFunction = function(a, b) {
return (+($(b).text())) - (+($(a).text()));
}
var lis = $('ul.list li');
lis = Array.prototype.sort.call(lis, sortFunction);
for (var i = 0; i < lis.length; i++) {
$('ul.list').append(lis[i]);
}
Fiddle Link

Sort jQuery collection as usual array and then append each element back in correct order.
$(".list li").sort(function(a, b) {
return parseInt($(b).text(), 10) - parseInt($(a).text(), 10);
}).appendTo('.list');
http://jsfiddle.net/zMmWj/

Related

How to do a DOM sort of a UL with TypeScript in Angular2+ (without using ngFor)? [duplicate]

I have a set of three list items that I would like to automatically display from high to low on page load. Ideally using jquery or javascript.
<ul class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
Each list item needs its own ID because they each have individual background images. The numbers must text nodes so that a user can edit them.
This will probably be the fastest way to do it, since it doesn't use jQuery:
function sortList(ul){
var new_ul = ul.cloneNode(false);
// Add all lis to an array
var lis = [];
for(var i = ul.childNodes.length; i--;){
if(ul.childNodes[i].nodeName === 'LI')
lis.push(ul.childNodes[i]);
}
// Sort the lis in descending order
lis.sort(function(a, b){
return parseInt(b.childNodes[0].data , 10) -
parseInt(a.childNodes[0].data , 10);
});
// Add them into the ul in order
for(var i = 0; i < lis.length; i++)
new_ul.appendChild(lis[i]);
ul.parentNode.replaceChild(new_ul, ul);
}
Call the function like:
sortList(document.getElementsByClassName('list')[0]);
You can sort other lists the same way, and if you have other elements on the same page with the list class you should give your ul an id and pass it in using that instead.
Example JSFiddle
Edit
Since you mentioned that you want it to happen on pageLoad, I'm assuming you want it to happen ASAP after the ul is in the DOM which means you should add the function sortList to the head of your page and use it immediately after your list like this:
<head>
...
<script type="text/javascript">
function sortList(ul){
var new_ul = ul.cloneNode(false);
var lis = [];
for(var i = ul.childNodes.length; i--;){
if(ul.childNodes[i].nodeName === 'LI')
lis.push(ul.childNodes[i]);
}
lis.sort(function(a, b){
return parseInt(b.childNodes[0].data , 10) - parseInt(a.childNodes[0].data , 10);
});
for(var i = 0; i < lis.length; i++)
new_ul.appendChild(lis[i]);
ul.parentNode.replaceChild(new_ul, ul);
}
</script>
</head>
<body>
...
<ul class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
<script type="text/javascript">
!function(){
var uls = document.getElementsByTagName('ul');
sortList( uls[uls.length - 1] );
}();
</script>
...
</body>
You can try this
var ul = $(".list:first");
var arr = $.makeArray(ul.children("li"));
arr.sort(function(a, b) {
var textA = +$(a).text();
var textB = +$(b).text();
if (textA < textB) return -1;
if (textA > textB) return 1;
return 0;
});
ul.empty();
$.each(arr, function() {
ul.append(this);
});
Live example : http://jsfiddle.net/B7hdx/1
you can use this lightweight jquery plugin List.js cause
it's lightweight [only 3K script]
easy to implement in your existing HTML table using class
searchable, sortable and filterable
HTML
<div id="my-list">
<ul class="list">
<li>
<h3 class="name">Luke</h3>
</li>
<li>
<h3 class="name">John</h3>
</li>
</ul>
</div>
Javascript
var options = {
valueNames: ['name']
};
var myList = new List('my-list', options);
There's also this small jQuery plugin. Which would make your sort nothing more than:
$('.list>li').tsort({attr:'id'});
This code will sort that list assuming there is only one .list item:
function sortList(selector) {
var parent$ = $(selector);
parent$.find("li").detach().sort(function(a, b) {
return(Number(a.innerHTML) - Number(b.innerHTML));
}).each(function(index, el) {
parent$.append(el);
});
}
sortList(".list");
You can see it work here: http://jsfiddle.net/jfriend00/FjuMB/
To explain how it works:
It gets the .list parent object.
It finds all the <li> child objects.
It removes all the <li> child objects from the DOM, but preserves their data
It sorts the li objects using a custom sort function
The custom sort function gets the HTML in the li tag and converts it to a number
Then, traversing the array in the newly sorted order, each li tag is appended back onto the original parent.
The result is that they are displayed in sorted order.
Edit:
This improved version will even sort multiple list objects at once:
function sortList(selector) {
$(selector).find("li").sort(function(a, b) {
return(Number(a.innerHTML) - Number(b.innerHTML));
}).each(function(index, el) {
$(el).parent().append(el);
});
}
sortList(".list");
Demo: http://jsfiddle.net/jfriend00/RsLwX/
Non jquery version (vanilla javascript)
Benefits: the list is sorted in place, which doesn't destroy the LI's nor remove any events that may be associated with them. It just shuffles things around
Added an id to the UL:
<ul id="myList" class="list">
<li id="alpha">32</li>
<li id="beta">170</li>
<li id="delta">28</li>
</ul>
and the vanilla javascript (no jquery)
// Grab a reference to the UL
var container = document.getElementById("myList");
// Gather all the LI's from the container
var contents = container.querySelectorAll("li");
// The querySelector doesn't return a traditional array
// that we can sort, so we'll need to convert the contents
// to a normal array.
var list = [];
for(var i=0; i<contents.length; i++){
list.push(contents[i]);
}
// Sort based on innerHTML (sorts "in place")
list.sort(function(a, b){
var aa = parseInt(a.innerHTML);
var bb = parseInt(b.innerHTML);
return aa < bb ? -1 : (aa > bb ? 1 : 0);
});
// We'll reverse the array because our shuffle runs backwards
list.reverse();
// Shuffle the order based on the order of our list array.
for(var i=0; i<list.length; i++){
console.log(list[i].innerHTML);
container.insertBefore(list[i], container.firstChild);
}
And the fiddle proof: https://jsfiddle.net/L27gpnh6/1/
You can use this method:
var mylist = $('ul');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
var compA = $(a).text().toUpperCase();
var compB = $(b).text().toUpperCase();
return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });
Check the article here:
http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/
Edit: There is a very cool jquery plugin that does that : http://tinysort.sjeiti.com/
Something like this should help:
var $parent = $(".list");
$(".list li").sort(function (a, b) {
return window.parseInt($(a).text(), 10) - window.parseInt($(b).text(), 10);
}).remove().each(function () {
$parent.append($(this));
});
One method could be to sort an array (well, a jQuery object) of the li elements and replace the contents (using the html method) of the ul with the sorted array of elements:
$(".list").html($(".list li").sort(function(a, b) {
return parseInt($(b).text(), 10) - parseInt($(a).text(), 10);
}));
Here's a working example.
using jQuery for help:
var sortFunction = function(a, b) {
return (+($(b).text())) - (+($(a).text()));
}
var lis = $('ul.list li');
lis = Array.prototype.sort.call(lis, sortFunction);
for (var i = 0; i < lis.length; i++) {
$('ul.list').append(lis[i]);
}
Fiddle Link
Sort jQuery collection as usual array and then append each element back in correct order.
$(".list li").sort(function(a, b) {
return parseInt($(b).text(), 10) - parseInt($(a).text(), 10);
}).appendTo('.list');
http://jsfiddle.net/zMmWj/

jQuery Clone several "li" and append at a specific position of ul (not its end)

am developping a dynamic pagination bar , where the "li" are cloned n times depending of a number received from an external webservice.
here is my pagination element:
<ul class="pagination">
<li class="pagePrevious" name="previous">
<span aria-hidden="true">«</span>
</li>
<li class="page" name="1">1</li>
<li class="pageNext" name="next">
<span aria-hidden="true">»</span>
</li>
</ul>
evidently you may note that my first Li and my last Li inside the Ul are the button next and previous which are not cloned and they are statically always present .
my cloning fonction consits of selecting the last-1 child of the li which is directly the second , and clone it with dynamic incremental id , and finally its inserts it in the ul.
my fonction :
createPagination: function (nb) {
var lastLI = $('.pagination li').last().prev();
var num = lastLI.attr('name');
for (var i = num; i <= nb ; i++) {
if (i != num) {
var cloned = lastLI.clone().attr('name', i);
$(cloned).find('a').text(i);
$('ul').append(cloned);
}
}
}
my problem is how to make it append the cloned li always before the last li of next button. ???
note that i mays not change the name of class attribute for other specifications
Any suggestions ??
Use .before() to put something immediately before another element.
createPagination: function (nb) {
var nextLI = $('pagination .pageNext');
var lastLI = nextLI.prev();
var num = lastLI.attr('name');
for (var i = num+1; i <= nb ; i++) {
var cloned = lastLI.clone().attr('name', i);
cloned.find('a').text(i);
nextLI.before(cloned);
}
}
BTW, you don't need to write $(cloned), since cloned is already a jQuery object. And if you start the for loop at num+1, you don't need to check if (i != num).
the solution is to use simlply the fonction insertBefore instead of append :
var lastLI = $('.pagination li').last().prev();
var nextLI= $('.pagination li').last();
var num = lastLI.attr('name');
for (var i = num; i <= nb ; i++) {
if (i != num) {
var clone = lastLI.clone().attr('name', i);
$(clone).find('a').text(i);
clone.insertBefore(nextLI);
clone.removeClass("is-active")
}
}

jQuery UI sortable - Sort around stationary items [duplicate]

Is it possible to lock list items in JQuery sortable list in a way that those items will stay in that particular place in the list.
For example,
consider this pseudo list with locked items...
item A
item B(locked)
item C(locked)
item D
item E
item F
item G(locked)
So, I'd like to have the items B,C and G to be fixed in a way that if user drag and drop item D at the start of the list, the item A "jumps" over fixed/locked items B and C with following results...
item D
item B(locked)
item C(locked)
item A
item E
item F
item G(locked)
I've been searching for something like this without luck. Is it possible..?
Here's a hopefully bug-free version, updating as you drag. It's generating the current desired positions of the items when sorting starts, which means you should be able to change the classes whenever you need, refresh the widget's list items and you're good to go.
It also uses the sortable's built-in items property to prevent dragging the fixed items and to sort out any sorting problems at the top and the bottom of the list.
I tried to move the fixed items around, but that resulted in horribly buggy behaviour, especially when there are multiple fixed items in groups. The final solution detaches all fixed items from the list, adds a helper element to the front, then re-inserts the fixed elements to their desired position, which seems to fix all bugs.
Try the demo here: http://jsfiddle.net/PQrqS/1/
HTML:
<ul id="sortable">
<li>oranges</li>
<li class="static">apples</li>
<li>bananas</li>
<li>pineapples</li>
<li>grapes</li>
<li class="static">pears</li>
<li>mango</li>
</ul>
CSS:
.static { color:red; }
li { background-color:whitesmoke; border:1px solid silver; width:100px; padding:2px; margin:2px; }
Javascript:
$('#sortable').sortable({
items: ':not(.static)',
start: function(){
$('.static', this).each(function(){
var $this = $(this);
$this.data('pos', $this.index());
});
},
change: function(){
$sortable = $(this);
$statics = $('.static', this).detach();
$helper = $('<li></li>').prependTo(this);
$statics.each(function(){
var $this = $(this);
var target = $this.data('pos');
$this.insertAfter($('li', $sortable).eq(target));
});
$helper.remove();
}
});
I extended the jQuery.Ui.sortable:
Overview
jQuery.Ui.sortable widget extension with fixed feature. This feature allows user to fix elements in the list.
With the .fixedsortable() constructor you construct a .sortable() class which extended with the features. You can use the original methods and the extended as well.
Code
https://gist.github.com/3758329#file_fixedsortable.js > fixedsortable.js
Example
http://jsfiddle.net/omnosis/jQkdb/
Usage
General:
To use, add the fixed property to the sortable list optios:
$("#list").fixedsortable({
fixed: (value)
})
the value can be:
integer example: 3
array of integers example : [1,2,5]
a html element or a list of html elements
a css selector
jquery object
HTML:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> //the jquery
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script> //the original jquery-ui
<script type="text/javascript" src="https://raw.github.com/gist/3758329/91749ff63cbc5056264389588a8ab64238484d74/fixedsortable.js"></script> //the extended sortable
...
<ul id="sortable1">
<li>oranges</li>
<li class="static">apples</li>
<li>bananas</li>
<li>pineapples</li>
<li>grapes</li>
<li class="static">pears</li>
<li>mango</li>
</ul>
<ul id="sortable2">
<li>bananas</li>
<li foo="asd">oranges</li>
<li foo="dsa">apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
<ul id="sortable3">
<li>bananas</li>
<li>oranges</li>
<li>apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
Javascript
$(function() {
$("#sortable1").fixedsortable({
fixed: "> .static"
});
$("#sortable2").fixedsortable({
fixed: $("li[foo]").css("background","red")
});
$("#sortable3").fixedsortable({
fixed: 2
})
});
Notes:
If you insist to use the .sortable instead of .fixedsortable you can use this https://gist.github.com/3758329#file_sortable.js instead of the jquery.ui library. This is a complete replacement of the jQuery.ui, but i don't recommend to use this because of later updates.
i have been working on this more than 12 hours :( i am insane..
Check this out: Forcing an item to remain in place in a jQuery UI Sortable list
Also, I've implemented the above solution with multiple fixed elements here: http://jsfiddle.net/enBnH/12/ (obsolete, see below)
It's rather self-explanatory, i think.
EDIT:
I've automated the process for generating the lockto values as well as adding ID's to those lis with the class "fixed" (note that i have to add an ID so we can reference it)
See the COMPLETE solution HERE: http://jsfiddle.net/enBnH/44/
EDIT
Okay, after a gazillion errors with the above, i just rewrote the dang thing myself:
http://jsfiddle.net/thomas4g/GPMZZ/15/
NOTE: The above does work, but #DarthJDG's answer seems a lot nicer to me. I'm leaving mine up on the offchance someone might prefer how mine behaves (i've learned not to delete stuff just beceause there's a better version :P )
Using the items parameter you can achieve what you want like this:
$("#mytable tbody").sortable({items: 'tr.sortable'});
Only rows with a .sortable CSS class can be sorted now.
If you want to lock only the 1st row you can do this:
$("#mytable tbody").sortable({items: 'tr:not(:first)'});
The possibilities are endless...
This is based on #DarthJDG code. However it wasn't retrieving all the id's and the sorting wasn't working with the table. So I managed to update his solution which works with both list and tables and keeps the id in the array.
Javascript:
var fixed = '.static'; //class which will be locked
var items = 'li'; //tags that will be sorted
$('ul').sortable({
cancel: fixed,
items: items,
start: function () {
$(fixed, this).each(function () {
var $this = $(this);
$this.data('pos', $this.index());
});
},
change: function () {
var $sortable = $(this);
var $statics = $(fixed, this).detach();
var tagName = $statics.prop('tagName');
var $helper = $('<'+tagName+'/>').prependTo(this);
$statics.each(function () {
var $this = $(this);
var target = $this.data('pos');
$this.insertAfter($(items, $sortable).eq(target));
});
$helper.remove();
}
});
Demo: http://plnkr.co/edit/hMeIiRFT97e9FGk7hmbs
Connected sortables and fixed items
I ran into the problem when we have several connected sortables. The code suggested by #sarunast and #DarthJDG has erroneous behavior when dragging items from one list to another.
Therefore, I have modified it a little, and now you can drag items from different lists with saving positions in both of them.
javascript:
let connected = '.soratble';
let fixed = '.static';
let newParentContainer;
//wrap the code suggested by #sarunast and #DarthJDG into the function
//code was modified a little
function sortingAroundFixedPositions(container) {
let sortable = $(container);
let statics = $(fixed, container).detach();
let tagName = statics.prop('tagName');
let helper = $('<' + tagName + '/>').prependTo(container);
statics.each(function() {
let target = this.dataset.pos;
let targetPosition = $(tagName, sortable).eq(target);
if (targetPosition.length === 0) {
targetPosition = $(tagName, sortable).eq(target - 1)
}
$(this).insertAfter(targetPosition);
});
helper.remove();
}
$('ul').sortable({
connectWith: connected,
cancel: fixed,
start: function() {
$(fixed, connected).each(function() {
this.dataset.pos = $(this).index();
});
},
change: function(e, ui) {
sortingAroundFixedPositions(this);
if (ui.sender) {
newParentContainer = this;
}
if (newParentContainer) {
sortingAroundFixedPositions(newParentContainer);
}
},
update: function(e, ui) {
newParentContainer = undefined;
}
});
demo: http://plnkr.co/edit/blmv4ZjaWJFcjvO2zQH0
Just use the "Include/Exclude" items selectors.
Here is the link: https://jqueryui.com/sortable/#items
oh no! gist link is broken. here is code dump from https://gist.github.com/peterh-capella/4234752
code accessed Jan 6, 2016
//this code is created to fix this problem: http://stackoverflow.com/questions/4299241/
(function( $, undefined ) {
$.widget("ui.fixedsortable", $.ui.sortable, {
options: $.extend({},$.ui.sortable.prototype.options,{fixed:[]}),
_create: function() {
var o = this.options;
this.containerCache = {};
this.element.addClass("ui-sortable");
//Get the items
$.ui.sortable.prototype.refresh.apply(this,arguments);
if( typeof this.options.fixed == "number") {
var num = this.options.fixed
this.options.fixed = [num];
}
else if( typeof this.options.fixed == "string" || typeof this.options.fixed == "object") {
if(this.options.fixed.constructor != Array) {
var selec = this.options.fixed;
var temparr = [];
var temp = $(this.element[0]).find(selec);
var x = this;
temp.each(function() {
var i;
for(i=0;i<x.items.length && x.items[i].item.get(0) != this;++i) {}
if(i<x.items.length) temparr.push(i);
});
this.options.fixed = temparr;
}
}
//Let's determine if the items are being displayed horizontally
this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
//Let's determine the parent's offset
this.offset = this.element.offset();
//Initialize mouse events for interaction
$.ui.sortable.prototype._mouseInit.apply(this,arguments);
},
_mouseCapture: function( event ) {
this._fixPrev = this._returnItems();
return $.ui.sortable.prototype._mouseCapture.apply(this,arguments);
},
_mouseStart: function( event ) {
for(var i=0;i<this.options.fixed.length;++i) {
var num = this.options.fixed[i];
var elem = this.items[num];
if(event.target == elem.item.get(0)) return false;
}
return $.ui.sortable.prototype._mouseStart.apply(this,arguments);
},
_rearrange: function(event, i, a, hardRefresh) {
a ? a[0].appendChild(this.placeholder[0]) :
i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
this._refix(i);
//Various things done here to improve the performance:
// 1. we create a setTimeout, that calls refreshPositions
// 2. on the instance, we have a counter variable, that get's higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
// 4. this lets only the last addition to the timeout stack through
this.counter = this.counter ? ++this.counter : 1;
var self = this, counter = this.counter;
window.setTimeout(function() {
if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
},0);
},
_refix: function(a) {
var prev = this._fixPrev;
var curr = this._returnItems();
var Fixcodes = this.options.fixed;
var NoFixed = [];
var Fixed = [];
var Mixed = []
var post = [];
for(var i=0;i<Fixcodes.length;++i) {
var fix_index = Fixcodes[i];
var fix_item = prev[fix_index];
var j = 0;
for(j=0;j<curr.length && curr[j].item.get(0) != fix_item.item.get(0);++j) {}
curr.splice(j,1);
Fixed.push(fix_item);
}
for(var i=0;i<curr.length;++i) {
if(curr[i].item.get(0) != this.currentItem.get(0)) {
NoFixed.push(curr[i]);
}
}
var fix_count = 0;
var nofix_count = 0;
for(var i=0;i<Fixed.length + NoFixed.length;++i) {
if(Fixcodes.indexOf(i) >= 0) {
Mixed.push(Fixed[fix_count++]);
}
else {
Mixed.push(NoFixed[nofix_count++]);
}
}
var parent = this.currentItem.get(0).parentNode;
var allchild = parent.children;
for(var i=0;i<Mixed.length;++i) {
parent.removeChild(Mixed[i].item.get(0));
parent.appendChild(Mixed[i].item.get(0));
}
},
_returnItems: function(event) {
this.containers = [this];
var items = [];
var self = this;
var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
var connectWith = $.ui.sortable.prototype._connectWith.apply;
if(connectWith) {
for (var i = connectWith.length - 1; i >= 0; i--){
var cur = $(connectWith[i]);
for (var j = cur.length - 1; j >= 0; j--){
var inst = $.data(cur[j], 'sortable');
if(inst && inst != this && !inst.options.disabled) {
queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
this.containers.push(inst);
}
};
};
}
for (var i = queries.length - 1; i >= 0; i--) {
var targetData = queries[i][1];
var _queries = queries[i][0];
for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
var item = $(_queries[j]);
item.data('sortable-item', targetData); // Data for target checking (mouse manager)
items.push({
item: item,
instance: targetData,
width: 0, height: 0,
left: 0, top: 0
});
};
};
return items;
},
value: function(input) {
//console.log("test");
$.ui.sortable.prototype.value.apply(this,arguments);
}
});
})(jQuery);
And dumping rest of his answer, just in case
dependencies
https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js
https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js
Script
function randomColor() { //for a little fun ;)
var r = (Math.floor(Math.random()*256));
var g = (Math.floor(Math.random()*256));
var b = (Math.floor(Math.random()*256));
return "#" + r.toString(16) + g.toString(16) + b.toString(16)
}
$(function() {
$("#sortable1").fixedsortable({
fixed: "> .static", //you can use css selector
sort: function() { //you can add events as well, without getting confused. for example:
$(".static").css("background",randomColor()) //change the fixed items background
},
change: function(event,ui) {
$(ui.item[0]).css("border","2px solid "+randomColor()) //change the captured border color
},
stop: function(event,ui) {
$(ui.item[0]).css("border","2px solid #777"); //change the back the css modifications
$("#sortable1 > li.static").css("background","#aaa");
}
});
$("#sortable2").fixedsortable({ //you can use jQuery object as selector
fixed: $("li[foo]").css("background","red")
});
$("#sortable3").fixedsortable({
fixed: [2,4], //you can use array of zero base indexes as selector
update: function(event, ui) {
alert($(this).fixedsortable('toArray')) //the fixedsortable('toArray') also works
}
})
$("#sortable4").fixedsortable({
fixed: 5 //you can fix a single item with a simple integer
})
});
HTML
<body>
<div style="width:120px;float:left;">
<ul id="sortable1">
<li>oranges</li>
<li class="static">apples</li>
<li>bananas</li>
<li>pineapples</li>
<li>grapes</li>
<li class="static">pears</li>
<li>mango</li>
</ul>
<ul id="sortable2">
<li>bananas</li>
<li foo="asd">oranges</li>
<li foo="dsa">apples</li>
<li>pineapples</li>
<li>grapes</li>
<li>pears</li>
<li>mango</li>
</ul>
</div>
<div style="width:120px;float:left;">
<ul id="sortable3">
<li id="fru_1">bananas</li>
<li id="fru_2">oranges</li>
<li id="fru_3" style="background:#f4f">apples</li>
<li id="fru_4">pineapples</li>
<li id="fru_5" style="background:#faaba9">grapes</li>
<li id="fru_6">pears</li>
<li id="fru_7">mango</li>
</ul>
<ul id="sortable4">
<li>bananas</li>
<li>oranges</li>
<li>apples</li>
<li>pineapples</li>
<li>grapes</li>
<li style="background:#dada00">pears</li>
<li>mango</li>
</ul>
</div>
</body>
CSS
ul {margin:10px;}
ul#sortable1 > li, ul#sortable2 > li, ul#sortable3 > li, ul#sortable4 > li {
display:block;
width:100px;
height:15px;
padding: 3px;
background: #aaa;
border: 2px solid #777;
margin: 1px;
}
ul#sortable1 > li.static {
opacity:0.5;
}
Maybe this will help to someone: use methods "disable" and "enable". Example
HTML:
<ul class="sortable">
<li>You can move me</li>
<li data-state="lifeless">You can't move me.</li>
</ul>
Script:
$('#sortable').sortable();
$('#sortable').mousedown(function() {
if($(this).data('state')=='lifeless') $('#sortable').sortable('disable');
else $('#sortable').sortable('enable');
});
Live example here: https://jsfiddle.net/ozsvar/0ggqtva5/2/
There is a slightly better way to solve this.
You need to use a grid instead of a list and then you can fix the position of an element by declaring where the element should be arranged with css:
.fixed-element {
grid-column-start: 1;
grid-column-end: 1;
grid-row-start: 1;
grid-row-end: 1;
}

Change list elements index with jQuery

I hava a list:
<ul>
<li class="item_1">element</li>
<li class="item_2">element</li>
<li class="item_3">element</li>
</ul>
After some drag and drop action i'm switching elements positions, so after this my list looks like this:
<ul>
<li class="item_2">element</li>
<li class="item_3">element</li>
<li class="item_1">element</li>
</ul>
I need to replace classes of this elements after this dragging action to get sorted list again - state before dragging.
So, i'm doing this:
var setItemNumber = function(item) {
item.each(function(i) {
$(this).removeAttr('class').attr('class', 'item_' + (i + 1));
});
}
What is happening is that elements are changing classes but their are in the same positions, it looks like they doesn't change index and this iteration is acting on previous DOM list state.
How can i change this, or maybe something else? Can anyone help?
I guess what you are you looking for is this:
reindexItems = function() {
var items = $('ul li');
var i = 1;
items.each(function() {
$(this).removeAttr('class').attr('class', 'item_' + i++);
});
}
If you just need to rename the classes then you can do for example
var elements = $("li");
for(var i=0; i<elements.length; i++){
$(elements[i]).attr("class", "item_" + i);
}
If you are planning to reorder elements in DOM changing class names wont work. You have to actually sort them and since you are using Jquery
var setItemNumber = function(item) {
$(item).sort(function(a,b){
var an = a.attr('class').replace("item_","")
bn = b.attr('class').replace("item_","");
if(an > bn) {
return 1;
}
if(an < bn) {
return -1;
}
return 0;
});
}
I wrote some solution also:
var setItemIndex = function(item) {
// iterate each marked item
item.each(function() {
// get index of item
var i = $(this).index();
// set new index based on item class
$(this)
.removeAttr('class')
.attr('class', 'item_' + (i));
});
};

Pure javascript way to update CSS class attribute from all list items?

I'd like to use Javascript (not jquery) to access all items in a <ul> list and remove the active class from everything except my chosen menu item.
Here is the list:
<ul id='flash-menu'>
<li id="menu1" class='something active'>item 1</li>
<li id="menu2" class='somethingelse'>item 2</li>
<li id="menu3" class='somethingelse'>item 3</li>
</ul>
This is my javascript:
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0 ; i<list_items.length ; i++){
list_items[i].className = list_items[i].className.replace('/\bactive\b/','');
}
document.getElementById(view_name).className += " active";
}
The last line of the Javascript (adding the active class) works, but I don't think I'm accessing the list items right to remove the classes from the other items. Any suggestions? - thanks!
First off, your regex is wrong:
list_items[i].className.replace(/\bactive\b/, '');
Note: No quotes on regex'es in JavaScript. A slighty altered, working version is available on JsFiddle.
Furthermore, I get a few instances of HTMLTextElements in list_items. They're breaking the loop (Fx3.6/Win7) when trying to access the non-existing className attribute. You can avoid this by either using:
var list_items = document.getElementById('flash-menu').getElementsByTagName('li');
// Selecting _all_ descendant <li> elements
or by checking for the existence of .className before read/write within the loop body (example). The latter is probably the cleanest choice since it still only affects direct children (you may have several levels of <ul>s in each <li>).
I.e.,
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').childNodes;
for (var i=0, j=list_items.length; i<j; i++){
var elm = list_items[i];
if (elm.className) {
elm.className = elm.className.replace(/\bactive\b/, '');
}
}
document.getElementById(view_name).className += ' active';
}
You can use javascript function getElementsByTagName:
var listitems = document.getElementsByTagName("li");
this would return an array of all the lists and can be iterated for each list element and processed as required.
You can try:
In the case that you can have more than ul, first you have to get all references to them and then process each ul:
var uls = document.getElementsByTagName("ul");
for (uli=0;uli<uls.length;uli++) {
ul = uls[uli];
if (ul.nodeName == "UL" && ul.className == "classname") {
processUL(ul);
}
}
An illustration of proccessUL can be:
function processUL(ul) {
if (!ul.childNodes || ul.childNodes.length == 0) return;
// Iterate LIs
for (var itemi=0;itemi<ul.childNodes.length;itemi++) {
var item = ul.childNodes[itemi];
if (item.nodeName == "LI") {
// Iterate things in this LI
in the case that you need it put your code here
.....
}
}
}
Of course you can also use: item.className = "classname"; if you dont need to iterate between childs of LI
document.getElementById('flash-menu').childNodes will also include white space nodes.
function updateMenu(view_name) {
var list_items = document.getElementById('flash-menu').getElementsByTagName('li'), i;
for (i=0 ; i<list_items.length ; i++){
if (list_items[i].className.indexOf('active') > -1) {
list_items[i].className = list_items[i].className.replace(/\bactive\b/,'');
}
}
document.getElementById(view_name).className += " active";
}
i agree with jensgram,and you'd better code like this:
list_items[i].className.replace(/\bactive\b/g, '');
add the regex string a 'g'
g is for Global ,using ‘/g’ can replace all the same Which Match the regex ,but if you don't use '/g',you just replace the first string .
like this :
var test= "testeetest" ;
alert(test.replace(/e/,"")) ;//result
: tsteetest but using 'g' var
test= "testeetest" ;
alert(test.replace(/e/g,"")) ;//result
: tsttst
Have a look at this here: https://developer.mozilla.org/en-US/docs/Web/API/element.classList
It helped me a lot with finding class elements!
This is my solution, maybe not the best, but for my works fine.
window.addEventListener('load', iniciaEventos, false);
function iniciaEventos(e)
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++ )
{
menu[i].addEventListener('mousedown', clickMenu);
}
}
function clickMenu()
{
var menu = document.querySelectorAll('nav li');
for(var i = 0; i < menu.length; i++)
menu[i].classList.remove('active');
this.classList.add('active');
}

Categories

Resources