jQuery Exact Number Match For Table Sort - javascript

I'm building a jQuery table sorting script. Yes, yes, I know there are plug-ins for that, but where's the fun in ridding someone else's coat tails (not to mention an entire lack of learning and understanding)?
So I've got a good sort going on for alpha types, I'm now working on a numeric sort.
So quick down and dirty. I get the column values and push them into an array:
var counter = $(".sort tr td:nth-child("+(columnIndex+1)+")").length;
for (i = 1; i <= counter; i++) {
columnValues.push($(".sort tr:eq("+i+") td:eq("+columnIndex+")").text());
}
I then sort they array:
columnValues.sort(function(a,b){
return a-b
});
I then check for unique entries (this was mainly for same names):
$.each(columnValues, function(i, el){
if($.inArray(el, uniqueColumns) === -1) uniqueColumns.push(el);
});
I then use the array as a list of keys to get the data from the table and push into another array. This is where the problem comes in. For names it works just fine, but with number (i.e. 3, 30, 36) it doesn't. With the sorted list starting with 3 it sees the 3 in the 30 and/or 36 and grabs it.
Here is what I have tried:
for (i = 0; i < counter; i++) {
var key = uniqueColumns[i];
$(".sort tr:contains("+key+") td").each(function(){
rowValues.push($(this).text());
});
}
And:
for (i = 0; i < counter; i++) {
var key = uniqueColumns[i];
$(".sort tr td").filter(function(i){
if($(this).text() === key) {
rowValues.push($(this).text());
}
});
}
Here is the fiddle running the code with the first set of code (which works better then the second):
UPDATE:
Also just tried this (still not working, works for initial sort but not subsequent):
for (i = 0; i < counter; i++) {
var key = uniqueColumns[i];
var found = false;
$(".sort tr:contains("+key+")").filter(function(j){
$(this).children().each(function(){
if ($(this).text() === key) {
found = true;
}
});
$(this).children().each(function(){
if (found) {
rowValues.push($(this).text());
}
});
});
}

Figured it out on my own. Decided on a completely different approach. I created a multidimensional array out of the table data, then created a custom sort function that works for both numeric and alpha data. Here is the function that gets the data, sorts the data, and rewrites the table.
function sort(column) {
var columnIndex = $(column).index(),
rowValues = [];
/* Get Data */
$(".sort tr").not(":first-child").each(function () {
var innerArray = [];
$(this).find('td').each(function () {
innerArray.push($(this).text());
});
rowValues.push(innerArray);
});
/* Sort Data */
rowValues.sort((function(index){
return function(a, b){
if (!isNaN(a[index])) {
a[index] = parseInt(a[index]);
}
if (!isNaN(b[index])) {
b[index] = parseInt(b[index]);
}
return (a[index] === b[index] ? 0 :
(a[index] < b[index] ? -1 : 1));
};
})(columnIndex));
/* Replace Data */
$(".sort tr").not(":first-child").each(function(i){
$(this).find("td").each(function(j){
$(this).replaceWith("<td>"+rowValues[i][j]+"</td>");
});
});
}

Related

Live Search Filter with Multiple Words, Use AND instead of OR

I have a live search autocomplete filter that I'm using to weed out a directory of people. Using this search, I want people to be able to search using multiple words, which will further reduce the number of results they get.
Currently, with the code below, if someone searches "technician Atlanta", they will get the directoryprofile divs that contain "technician" and the ones that contain "Atlanta". What I want is for it to find a div that contains BOTH of those words...so they can find a technician that is in Atlanta. Hopefully that makes sense.
My code is working for including the terms separately, but I want them to find rows containing multiple terms. Any ideas? THANKS in advance!!
$("#filter").keyup(function () {
// Split the current value of the filter textbox
var data = this.value.split(" ");
// Get the table rows
var rows = $(".directoryprofile");
if (this.value == "") {
rows.show();
return;
}
// Hide all the rows initially
rows.hide();
// Filter the rows; check each term in data
rows.filter(function (i, v) {
for (var d = 0; d < data.length; ++d) {
if ($(this).is(":contains('" + data[d] + "')")) {
return true;
}
}
return false;
})
// Show the rows that match.
.show();
});
rows.filter(function(i, v) {
var truth = true;
for (var d = 0; d < data.length; ++d) {
//remain true so long as all of the filters are found
//if even one is not found, it will stay false
truth = truth && $(this).is(":contains('" + data[d] + "')");
}
return truth;
})
//OR you could just flip your logic and return false if any of the
//filters are not found
rows.filter(function(i, v) {
for (var d = 0; d < data.length; ++d) {
if (!$(this).is(":contains('" + data[d] + "')")) {
return false;
}
}
return true;
})

Save multiple entries to same post in local storarge

I'm trying to save a shopping cart to local storage but having trouble to save it as I the way I want it to be saved. For each added order with the same id, the amount should increase and not create another duplicate of the input. I've got this semi-working with the first item/order but when I order more items they lay in the first order. And when I put the first order in again, it puts itself at the back and increases the amount in a weird way. Thankful for any help as I tried to fix this a couple of days now and tried a lot of different stuff with different results.
From local storage:
Button with id 88 pressed 4 times:
[{"id":"88","amount":4}]
Button with id 79 pressed 4 times:
[{"id":"88","amount":4},{"id":"79","amount":5}
,{"id":"79","amount":4},{"id":"79","amount":3},{"id":"79","amount":2}]
Then I press the button with id 88 again ONE time:
[{"id":"88","amount":5},{"id":"79","amount":5},{"id":"79","amount":4},
{"id":"79","amount":3},{"id":"79","amount":2},{"id":"88","amount":5},
{"id":"88","amount":5},{"id":"88","amount":5},{"id":"88","amount":5}]
And here is my javascript:
$("#btnBuyMovie").on("click", function () {
var movieId = getParameterByName("productId");
var amount = 1;
if (localStorage.getItem("shoppingCart") !== null) {
shoppingCartFromLS = JSON.parse(localStorage.getItem("shoppingCart"));
var newShoppingCart = new ShoppingCart(movieId, amount);
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId != shoppingCartFromLS[i].id) {
shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
}
}
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId == shoppingCartFromLS[i].id) {
shoppingCartFromLS[i].amount++;
}
}
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
} if (localStorage.getItem("shoppingCart") == null) {
var shoppingCartFromLS = [];
newShoppingCart = new ShoppingCart(movieId, amount);
shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));
}
Problem
Following for-loop has multiple problems
This line doesn't look correct.
Assuming you meant it to be this way, there is a semicolon at the end of it and it is pushing a shopping cart to the result of push function
if (movieId != shoppingCartFromLS[i].shoppingCartFromLS.push(newShoppingCart);
Assuming the above line is what you meant it to be, you are checking if every item is not the same item you are looking for.
So, if that item is not found on any iteration, you add that item again.
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId != shoppingCartFromLS[i].shoppingCartFromLS.push(newShoppingCart);
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS)); //this will happen for every item except the item that matches
}
}
Finally, this for-loop isn't required
for (var i = 0; i < shoppingCartFromLS.length; i++) {
if (movieId == shoppingCartFromLS[i].id) {
shoppingCartFromLS[i].amount++;
}
}
Solution
You need to optimize your code this way
var isFound = shoppingCartFromLS.some( function( item ){
var isFound = item.id == movieId; //this line is updated
item.amount += isFound ? 1 : 0;
return isFound;
})
if (!isFound)
{
shoppingCartFromLS.push( { id : movieId, amount : 1 } )
}
localStorage.setItem("shoppingCart", JSON.stringify(shoppingCartFromLS));

Total of different currencies from a json file

Currently working on an application which requires to display a set of values in different currencies. This is part of an application but everything I provide here should be enough as this is the main section I am working with. I have a json file which is read in and it is stored into an array called valuesArray, this array has all the information, such as the amount, currency, etc. With the currencies being sorted with highest first to the lowest on display like this:
EUR 500.00
USD 200.00
This is the code that I have created but it seems like this wouldn't be effective the more currencies I have. I've just put an array declaration above the function but just above this function is where I do all the json stuff and adding it into the array. $scope.valuesArray has data at this point.
$scope.valuesArray =[];
$scope.total = function()
{
var eur_total = 0;
var usd_total = 0;
if (typeof $scope.valuesArray != 'undefined')
{
var length = $scope.valuesArray.length;
for (var i = 0; i<length ; i++)
{
switch($scope.valuesArray[i].currency)
{
case "USD":
usd_total += parseFloat($scope.valuesArray[i].value);
break;
default:
eur_total += parseFloat($scope.valuesArray[i].value);
break;
}
}
}
var cost_total= [usd_total,eur_total];
total.sort(function(a, b){return b-a});
return format_to_decimal(total[0]) + "\x0A" + format_to_decimal(total[1]);
}
In my for loop I go through every single data in the array and break each currency down within the switch statement and finding the total amount of each currencies.
The last bit is kind of temporary as I couldn't figure out a different way of how to do it. I sort the totals for the currencies I have from the highest at the top.
I return the function with a function call for format_numeric_with_commas which gives me the value in proper currency format and this displays the value. Will update this and add that code when I get to it. But I have used the indexes as a rough logic to show what I want to get out of it. So in this case, total[0] should be 500.00 and total[1] should be 200.00.
On top of this I want to be able to display the currency type for each. So like the example above.
You can try to save all the calculations in the array with currency index.
$scope.valuesArray = [];
$scope.total = function () {
var totalsArray = [];
if (typeof $scope.valuesArray != 'undefined') {
var length = $scope.valuesArray.length
for (var i = 0; i < length; i++) {
if (!totalsArray[$scope.valuesArray[i].currency]) {
totalsArray[$scope.valuesArray[i].currency] = 0;
}
totalsArray[$scope.valuesArray[i].currency] += $scope.valuesArray[i].value;
}
}
var cost_total = [];
for (var k in totalsArray) {
cost_total.push(currency:k,value:totalsArray[k]);
}
cost_total.sort(function (a, b) {
return b.value - a.value
});
return format_to_decimal(cost_total[0].value)+cost_total[0].currency + "\x0A" + format_to_decimal(cost_total[1].value);

Array text to numbers, find matching values and sort

I have an array which looks like this:
["1,8", "4,6,8", "8,9", "6,9"]
1/ I would like to turn it in to this
[1,8,4,6,8,8,9,6,9]
2/ I would then like to find matching values, by looking for the most number:
[8]
This first has been solved with this:
var carArray = ["1,8", "4,6,8,7,7,7,7", "8,9", "6,9"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
setResult('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
}
else{
//3)/4) ???
setResult('sorting?');
}
//below is only for test display purposes
function setResult(res){
console.log(res);
}
3/ If the are no matching values like this
[1,8,4,6,5,7]
4/ Then I need to compare this array to another array, such as this
[6,7,4,1,2,8,9,5]
If the first number in <4> array above appears in <3> array, then get that number, ie in the above example I need to get 6. The <4> array will be static values and not change. The numbers is <3> will be dynamic.
EDIT Not the most elegant of answers, but I do have something working now. I didn't compare the original array directly with the second array, instead used simple if/else statements to do what I needed:
var carArray = ["1,5", "4", "8,2", "3,9,1,1,1"];
//1) create single array
var arr = carArray.join().split(',');
//2) find most occurring
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
if(maxOccurring){
//there was an element more than once, maxOccuring contains that element
console.log('Most occuring: ' + maxOccurring + ' (' + max + ' times)');
console.log(maxOccurring);
}
else {
// If not occuring, match from a list
if(jQuery.inArray("6", arr) !== -1) { console.log('6'); }
else if(jQuery.inArray("9", arr) !== -1) { console.log('9'); }
else if(jQuery.inArray("7", arr) !== -1) { console.log('7'); }
else if(jQuery.inArray("5", arr) !== -1) { console.log('5'); }
else if(jQuery.inArray("4", arr) !== -1) { console.log('4'); }
else if(jQuery.inArray("1", arr) !== -1) { console.log('1'); }
else { console.log('not found'); }
}
Example Fiddle
Step 1 is fairly easy by using javascript's join and split methods respectively:
var arr = carArray .join().split(',');
For step 2, several methods can be used, the most common one using an object and using the elements themselves as properties. Since you only need to get the most occurring value if there is a reoccurring value, it can be used in the same loop:
var counts = {}; //object to hold count for each occurence
var max = 0, maxOccurring;
arr.forEach(function(el){
var cnt = (counts[el] || 0); //previous count
counts[el] = ++cnt;
if(cnt > max && cnt > 1){ //only register if more than once (cnt>1)
max=cnt;
maxOccurring = el;
}
});
After the above, the variable maxOccurring will contain the reoccurring value (if any) and max will contain the times it occured
For step 4 the easiest way is to loop through the compare array and get the element that occurs in the input array:
var cmpArr = ['6','7','4','1','2','8','9','5'];
//find the first occurrence inside the cmpArr
res = function(){ for(var i= 0 ; i < cmpArr.length; i++){ if(arr.indexOf(cmpArr[i]) !== -1)return cmpArr[i];}}();
The above uses an in place function which is called immediately to be able to use return. You could also just use a loop and assign res when found, then break from the loop.
Last update, an alternate fiddle where the above is converted to a single function: http://jsfiddle.net/v9hhsdny/5/
Well first of all the following code results in four matching answers since the jQuery selectors are the same.
var questionAnswer1 = $(this).find('input[name=questionText]').val();
var questionAnswer2 = $(this).find('input[name=questionText]').val();
var questionAnswer3 = $(this).find('input[name=questionText]').val();
var questionAnswer4 = $(this).find('input[name=questionText]').val();
var carArray = [questionAnswer1, questionAnswer2, questionAnswer3, questionAnswer4];
You could use the eq(index) method of jQuery to select the appropriate element. However having 4 inputs with the same name is a bad practice.
Well lets say that the carArray has 4 different values which all consist out of comma separated numbers. You could then do the following:
var newArr = [];
carArray.forEach(function(e) {
e.split(",").forEach(function(n) {
newArr.push(n);
});
});
Well then we got to find the most occurring number. JavaScript doesn't have any functions for that so we will have to find an algorithm for that. I found the following algorithm on this stackoverflow page
var count = function(ary, classifier) {
return ary.reduce(function(counter, item) {
var p = (classifier || String)(item);
counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;
return counter;
}, {})
}
var occurances = count(newArr);
It isn't clear to me what you're trying to do in step 3 and 4, so can't answer those at the moment.
var ary = ["1,8", "4,6,8", "8,9", "6,9"];
var splitted = ary.reduce(function(acc, item) {
return acc.concat(item.split(','));
}, []);
var occurences = splitted.reduce(function(acc, item) {
if (!acc.hasOwnProperty(item)) acc[item] = 0;
acc[item] += 1;
return acc;
},{}),
biggest = Object.keys(occurences).reduce(function (acc, key) {
if (occurences[key] > acc.occurences) {
acc.name = key;
acc.occurences = occurences[key];
}
return acc;
},{'name':'none','occurences':0}).name;
var vals=["1,8", "4,6,8", "8,9", "6,9"];
// 1) turn into number array
var arrNew=[];
for(var i=0; i<vals.length; i++)
{
arrLine=vals[i].split(",");
for (var j=0;j<arrLine.length;j++) { arrNew.push (parseInt(arrLine[j])) }
}
//result:
alert(arrNew.join(";");
// 2) find most common
var found=[];
for(var i=0; i<arrNew.length; i++) {
// make an array of the number of occurrances of each value
if (found["num"+newArray[i]]) {
found["num"+newArray[i]] ++ ;
} else {
found["num"+newArray[i]]=1;
}
}
var mostCommon={count:0,val:"ROGUE"};
for (x in found) {
if (found[x] > mostCommon.count) {
mostCommon.count=found[x].count;
mostCommon.val=x;
}
}
// result :
alert(mostCommon.val);
//3) not quite sure what you meant there
// 4) unique values:
// at this point the 'found' list contains unique vals
var arrUnique=[];
for (x in found) {
arrUnique.push[x];
}
// result :
alert(arrUnique.join(";"))
//sort:
arrUnique.sort(function(a, b){return a-b});
(This won't work in most browsers) but on a side note, when ES6 becomes widely supported, your solution could look like this:
var arr1 = ["1,8", "4,6,8", "8,9", "6,9"];
var arr2 = arr1.join().split(',');
var s = Array.from(new Set(arr2)); //Array populated by unique values, ["1", "8", "4", "6", "9"]
Thought you might like to see a glimpse of the future!
1.
var orgArray = ['1,8', '4,6,8', '8,9', '6,9'];
var newArray = [];
for (var i in orgArray) {
var tmpArray = orgArray[i].split(',');
for (var j in tmpArray) {
newArray.push(Number(tmpArray[j]));
}
}
2.
var counts = {};
var most = null;
for (var i in newArray) {
var num = newArray[i];
if (typeof counts[num] === 'undefined') {
counts[num] = 1;
} else {
++(counts[num]);
}
if (most == null || counts[num] > counts[most]) {
most = num;
} else if (most != null && counts[num] === counts[most]) {
most = null;
}
}
I don't understand the question 3 and 4 (what "unique order" means) so I can't answer those questions.

Compare 2 records on screen with javascript

Im looking for a way to compare 2 json records on screen. The way i want is that, i want to show these 2 records side by side and mark the matched or unmatched properties.
Is there a library that does it already, and if not, how can i do it ??
Edit
My goal is to identify the same/different properties & to show them to users with different styles, rather than comparing the objects as a whole.
Someone made a jQuery plugin for this - jQuery.PrettyTextDiff.
https://github.com/arnab/jQuery.PrettyTextDiff
$("input[type=button]").click(function () {
$("#wrapper tr").prettyTextDiff({
cleanup: $("#cleanup").is(":checked")
});
});
JSFiddle
Here is a quick JavaScript function to help you compare the to JSON strings.
First, it checks that they have same number of properties, then compares that they have the same properties (by name) and then it compares the values.
You may want to tweak the value comparison (to allow for undefined or null).
Hope it is a good starter for you.
<script type="text/javascript">
var so = {}; // stackoverflow, of course.
so.compare = function (left, right) {
// parse JSON to JavaScript objects
var leftObj = JSON.parse(left);
var rightObj = JSON.parse(right);
// add object properties to separate arrays.
var leftProps = [];
var rightProps = [];
for(var p in leftObj) { leftProps.push(p); }
for(var p in rightObj) { rightProps.push(p); }
// do they have the same number of properties
if (leftProps.length != rightProps.length) return false;
// is every right property found on the left
for (var r = 0; r < rightProps.length; r++) {
var prop = rightProps[r];
if (leftProps.indexOf(prop) < 0) {
return false;
}
}
// is every left property found on the right
for (var r = 0; r < leftProps.length; r++) {
var prop = leftProps[r];
if (rightProps.indexOf(prop) < 0) {
return false;
}
}
// do the values match?
for (var q = 0; q < leftProps.length; q++) {
var propname = leftProps[q];
var leftVal = leftObj[propname];
var rightVal = rightObj[propname];
if (leftVal != rightVal) {
return false;
}
}
return true;
}
</script>

Categories