Sorting a HTML structure - javascript

Im trying to sort a div structure based on a paramter using a small javscript i found.
It seems to not perform exactly as expected. I understand the sorting function is not parsing the values perfectly...
This is the sorting logic is use...
<script type="text/javascript">
// Sorting Logic
$(function() {
$("a[href*=#]").click(function(e) {
e.preventDefault();
var liContents = [];
$('#ProductPrice span[id*="ABSPrice"]').each(function() {
liContents.push($(this).html());
});
liContents.sort(numOrdDesc);
$('#ProductPrice span[id*="ABSPrice"]').each(function() {
$(this).html(liContents.pop());
});
});
});
function numOrdDesc(a, b) {
return (parseInt(b) - parseInt(a));
}
// End
of Sorting Logic
Since i cannot exactly post the html i am going to add a link to the actual website where you can see this is action. Can anyone point out where i am going wrong?
http://www.absbiz.co.uk/Products/tabid/85/rvdsfcatid/Modems-437/Default.aspx
EDIT: Currently i think the sort is working, however i still cannot move the individual products. Only the prices get sorted and changed....

I took at look at your live site and injected the sorting function you used in your question. I noticed a few things. Firstly, the strings you are passing into your compare function look like this:
"£38.89 ex. VAT"
"£19.93 ex. VAT"
"£44.44 ex. VAT"
...
So parseInt("£38.89 ex. VAT") will return NaN. No compare. We can adjust this to remove all non-decimal information, and also parse a float instead, like so:
parseFloat("£38.89 ex. VAT".replace(/[^0-9\.]/g, "")); // --> 38.89
However, this will sort the above price strings, but we don't have association information on the products to properly sort them in the DOM (yet). For that we need to adjust what you put into your array.
The strategy is to find all the top item containers using $('.ProductListProductItem') and push their html into an array. Sort the array such that the prices are found by $('#ProductPrice span[id*="ABSPrice"]') and stripped of non-decimal information. Each top item container is then repopulated with the html from the sorted array.
Essential code:
var liContents = [];
// Push in all the product containers' innerHTML
$('.ProductListProductItem').each(function () {
liContents.push($(this).html());
});
// Use our new sorting routine
liContents.sort(numOrdDesc);
// Replace the html of each top item container
$('.ProductListProductItem').each(function () {
$(this).html(liContents.pop());
});
// Pass in jQuery elements, not strings
function numOrdDesc($a, $b) {
// Get the price further down in the DOM
var a = $('#ProductPrice span[id*="ABSPrice"]', $a).text();
var b = $('#ProductPrice span[id*="ABSPrice"]', $b).text();
return parseFloat(b.replace(/[^0-9\.]/g, "")) - parseFloat(a.replace(/[^0-9\.]/g, ""));
}
To verify this works, navigate to your live site and open DevTool > Console. Copy the above script and paste it into Console. Hit return, and note that the products are now sorted in ascending order. Enjoy.
Before:
After:

Your parseInt fails because of the pound sign. I'm guessing you want to strip that out in your sort function, and also use parseFloat instead since your prices are floating point numbers.
Try
function numOrdDesc(a, b) {
return parseFloat(b.replace(/[^0-9\.]/g, "")) - parseFloat(a.replace(/[^0-9\.]/g, ""))
}
The replace pretty much removes everything that's not a digit or a dot from the string before attempting to parse it
// "£298.73".replace(/[^0-9\.]/g, "") -> "298.73"
// parseFloat("298.73") -> 298.73

You are missing parameters to the function, you can do it like this.
liContents.sort(function(b, a) {
return (parseInt(b) - parseInt(a));
});

Related

Javascript sort list works only onve

I'm trying to implement a question like system.
The questions should reorder with every like based on the data attribute 'vote'.
So every time a like event is received from the sockets the sort function gets called.
The first time a question gets liked everything works fine and the list is sorted.
But then it stops sorting. I already checked the data values.
Here is my js function:
function sortQuestionList() {
$('#questionList li').sort(sort_li).appendTo('#questionList');
function sort_li(a, b) {
return ($(b).data('vote')) < ($(a).data('vote')) ? -1 : 1;
}
}
Your sort_li function doesn't return the values sort expects. It should return:
A negative number if a comes before b
A positive number if b comes before a
Zero if they're the same
Your code isn't doing that last thing. This makes sort unable to do its job correctly.
Instead:
function sortQuestionList() {
$("#questionList li").sort(sort_li).appendTo("#questionList");
function sort_li(a, b) {
return $(a).data("vote") - $(b).data("vote"); // ***
}
}
(That assumes that the value of vote is numeric.)
Your sort function works. However, it is not stable. You should write
function sort_li(a, b) {
return $(b).data("vote") - $(a).data("vote");
}
Anyways, this is not your problem.
I made an example here and its working just fine: https://codesandbox.io/s/sort-questions-stackoverlow-49hvi?file=/src/index.js
The code you provided is not the root of your problem.
We cannot provide any further help without a non working example. Please make a minimal pen or codesandbox.
All I can say is: Make sure you call the sort function everytime you update the list items. Make sure no other function overwrites those changes. Make sure you use the right properties ('data-votes' instead of 'votes').

onkeydown, and auto complete

I was wondering if anyone could help me solve this issue or point me towards the right direction.
In my project we have a filed that needs to be autofilled, at this moment I use onblur which works wonders as it only does it so once you leave the focus. However, due to recent changes, it needs to only do so when there is only one unique item in the map which it matches the input.
I have a large array defined as following:
var myArray = [
[content, content],
[content, content],
...
]
Later in my code I associate it with a map, at least this is what most stackoverflow questions I looked at referred to it as follows:
var myMap = {};
for(0 to myArray.length) {
var a = myArray[i][0];
var b = myArray[i][1];
myMap[a] = b;
}
Now, finally I iterate over this array as follows:
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0)
the above is the line of code I am struggling to figure out how to change. At this moment, while using on blur, if I type in the letter 'A' for example, and leave the focus area it will automatically fill it in with a certain name. However, in the array there are many other objects that begin with, or contain A. How can I change it so that the onkeydown event will keep going until it finally filters it down to to only possible key-value pair? I tried looking at MDN's documentation for filtering, but I do not think that will work for my purposes, or at least I am too inexperienced with JS.
If the indexOf the first and last are nonnegative and equal, there is just one. You could do this with an && and boolean short circuit evaluation, but that will run very far right off the screen, so I am showing your code with one more nested if (up to you to add the end of the block). But we also need to see if there are matches on multiple keys.
var matchCount=0;
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0){
if (map[key].toLowerCase().indexOf(location.toLowerCase()) == map[key].toLowerCase().lastIndexOf(location.toLowerCase())) {
matchCount++;
then outside your for loop:
if (matchCount==1){ //do your stuff

Removing '<and text within those>' from a string in javascript

I'm receiving an array of strings from a REST api call, and the strings have some html tags in them, for example:
Bard's opponents can also travel through his Magical Journey doorways. You can follow him, if you think it's safe.</li>
You can crush Bard's healing shrines just by walking over them. Don't let his allies take them without a fight.
Bard's ultimate, Tempered Fate, affects allies, enemies, monsters, and turrets alike. Sometimes it can be to your advantage to jump into it!</li>
Each line is a string, and two of them have an </li> tag at the end.
I tried writing a function that receives such an array, and returns a corrected array. Problem is, when I use it, the console in my website shows some weird errors with the strings from the array, and I've realized my function was the cause.
That is the function:
modal.removeBracketsFromArray = function (array) {
if (array == undefined)
return array;
function removeBracketsText(text) {
return text.replace(/<[^>]*>/g, '')
};
var newArray = [];
for (var i = 0; i < array.length; i++) {
newArray.push(removeBracketsText(array[i]));
}
return newArray;
};
It seems to do the work, but it somewhy messes up when using it in an ng-repeat attribute.
This is an use example:
<champion-ally-enemy-tips allytips="modalCtrl.removeBracketsFromArray(modalCtrl.champ.allytips)"
enemytips="modalCtrl.removeBracketsFromArray(modalCtrl.champ.enemytips)">
</champion-ally-enemy-tips>
which then moves to:
<ul>
<li ng-repeat="enemytip in enemytips"><h6>{{enemytip}}</h6></li>
</ul>
When I remove the method call (like so), it doesn't show an error, but the tags remain:
<champion-ally-enemy-tips allytips="modalCtrl.champ.allytips"
enemytips="modalCtrl.champ.enemytips">
</champion-ally-enemy-tips>
Is my function doing something weird without realizing it? thanks for helping
This is a pastebin of the errors I receive: LINK
Instead of messing with the array, how about creating a custom filter to strip out the HTML on display?
.filter('removeHTML', function() {
return function(input) {
return input.replace(/<[^>]*>/g, '');
}
})
Then change your display inside the ng-repeat to:
<h6>{{enemytip | removeHTML}}</h6>

Restricted JavaScript Array Pop Polyfill not working

I'm creating a few specific functions for a compiler I'm working on, But certain restrictions within the compiler's nature will prevent me from using native JavaScript methods like Array.prototype.pop() to perform array pops...
So I decided to try and write some rudimentary pseudo-code to try and mimic the process, and then base my final function off the pseudo-code... But my tests seem to fail... based on the compiler's current behavior, it will only allow me to use array.length, array element assignments and that's about it... My code is below...
pop2 = function(arr) {
if(arr.length>0){
for(var w=undefined,x=[],y=0,z=arr.length;y<=z;y++){
y+1<z?(x[y]=arr[y]):(w=arr[y],arr=x);
}
}
return w;
}
Arr = [-1,0,1,2];
// Testing...
console.log(pop2(Arr)); // undefined... should be 2
console.log(Arr); // [-1,0,1,2]... should be [-1,0,1]
I'm trying to mimic the nature of the pop function but can't seem to put my finger on what's causing the function to still provide undefined and the original array... undefined should only return if an initial empty array is sent, just like you would expect with a [].pop() call...
Anyone have any clues as to how I can tailor this code to mimic the pop correctly?
And while I have heard that arr.splice(array.length-1,1)[0]; may work... the compiler is currently not capable of determining splice or similar methods... Is it possible to do it using a variation of my code?
Thanks in advance...
You're really over-thinking [].pop(). As defined in the specs, the process for [].pop() is:
Get the length of the array
If the length is 0
return undefined
If length is more than 0
Get the item at length - 1
Reduce array.length by 1
Return item.
(... plus a few things that the JavaScript engine needs to do behind the scenes like call ToObject on the array or ensure the length is an unsigned 32-bit integer.)
This can be done with a function as simple as the one below, there's not even a need for a loop.
function pop(array) {
var length = array.length,
item;
if (length > 0) {
item = array[length - 1];
array.length -= 1;
}
return item;
}
Edit
I'm assuming that the issue with the compiler is that Array.prototype.pop isn't understood at all. Re-reading your post, it looks like arrays have a pop method, but the compiler can't work out whether the variable is an array or not. In that case, an even simpler version of this function would be this:
function pop(array) {
return Array.prototype.pop.call(array);
}
Try that first as it'll be slightly faster and more robust, if it works. It's also the pattern for any other array method that you may need to use.
With this modification, it works:
http://jsfiddle.net/vxxfxvpL/1/
pop2 = function(arr) {
if(arr.length>0){
for(var w=undefined,x=[],y=0,z=arr.length;y<=z;y++){
if(y+1<z) {
(x[y]=arr[y]);
} else {
(w=arr[y],arr=x);
break;
}
}
}
return w;
}
Arr = [-1,0,1,2];
// Testing...
console.log(pop2(Arr)); // 2
The problem now is to remove the last element. You should construct the original array again without last element. You will have problems with this because you can't modify the original array. That's why this tasks are maded with prototype (Array.prototype.pop2 maybe can help you)

How to create a pagination and sorting using jquery?

I need to create a pagination using jquery which displays 5 results per page. Also I must allow the user to sort the results by price.
I created the pagination and it works fine. The bug is in the sorting function. When the user sorts the results it just sorts the results available in the specific page and not the total results. Here is the demo
The below is the function to sort the price.
var ascending = false;
$('.sortc').on('click', '.sortp', function (e) {
e.preventDefault();
var sorted = $('ul .price_indiv').sort(function (a, b) {
return (ascending == (convertToNumber($(a).find('.final_price').html()) < convertToNumber($(b).find('.final_price').html()))) ? 1 : -1;
});
ascending = ascending ? false : true;
$('.price').html(sorted);
});
var convertToNumber = function (value) {
return parseFloat(value.replace('$', ''));
}
Can someone help me to fix this bug? NOTE: Without a plugin
I think you have misunderstood how the Pager works.You may need to re-evaluate how this script works. It displays the proper items and simply hides the rest of the list items using display:none;
Before Sort
!
After Sort
!
So as DarkHorse said sorting is working perfectly. All you need to do is just may be reapply sorting function to get it work

Categories

Resources