Jquery sort of table -> Numbers before text - javascript

I am working on a wait times API to show the current queuing times of the Disney-parks.
The wait times are loaded in a table in alphabetical order.
Now I have used the following code to sort this table on highest waits on top of the table to the lowest waits. That is what I want:
$(document).ready(function(){
var sorted = $('#mytable tbody tr').sort(function(b, a) {
var a = $(a).find('td:last').text(), b = $(b).find('td:last').text();
return a.localeCompare(b, false, {numeric: true})
})
$('#mytable tbody').html(sorted)
});
This works great, BUT as you can see in the image below the text values like 'Closed' and 'Refurbishment' are on top of the table, above the highest wait time.
How can I change this order of the table to get the highest wait times on top of the table and at last the text-values?
Current order, want to change this
So I want to get:
20 min.
15 min.
5 min.
Open
Closed
Refurbishment

To sort as you require, you need to sort differently dependent on whether the value is numeric or not. If both are numeric, compare as you currently do. Otherwise, if only one is numeric, sort that to the beginning; and if both are not numeric, sort according to your required order (Open, Closed, Refurbishment), which can be implemented by looking up the phrase in an object that defines the sort order:
var states = {
'Open': 0,
'Closed': 1,
'Refurbishment': 2
};
$(document).ready(function() {
var sorted = $('#mytable tbody tr').sort(function(b, a) {
var a = $(a).find('td:last').text(),
b = $(b).find('td:last').text();
if (!isNaN(parseInt(a))) {
if (!isNaN(parseInt(b))) {
// a and b both numeric
return a.localeCompare(b, false, {
numeric: true
});
} else {
// a numeric, b not, sort b last
return 1;
}
} else if (!isNaN(parseInt(b))) {
// a not numeric, b numeric, sort a last
return -1;
} else {
// a not numeric, b not numeric, sort regular
return states[b] - states[a];
}
});
$('#mytable tbody').html(sorted)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="mytable">
<tbody>
<tr>
<td>Challenge trails</td>
<td>Refurbishment</td>
</tr>
<tr>
<td>Camp Discovery</td>
<td>Open</td>
</tr>
<tr>
<td>Soaring</td>
<td>120 mins</td>
</tr>
<tr>
<td>Fantasia</td>
<td>20 mins</td>
</tr>
<tr>
<td>Shipwreck Shore</td>
<td>5 mins</td>
</tr>
<tr>
<td>Rex's Racer</td>
<td>105 mins</td>
</tr>
<tr>
<td>Slinky Dog</td>
<td>Closed</td>
</tr>
</tbody>
</table>

Related

Replace old value with new value excluding the children

The initial text of A, B, C, D, and the number need to be removed in the frontend because I require it in the backend.
The HTML structure of table row is like this:
<tr ng-repeat="(key, field) in nbd_fields" ng-show="field.enable && field.published" class="ng-scope">
<td class="ng-binding">A,B,C,D: 1 - Auswahl Wunschkarte : <b class="ng-binding">Wähle eine Option</b>
</td>
<td ng-bind-html="field.price | to_trusted" class="ng-binding"></td>
</tr>
Before Input:
Current Output:
If you notice that the selected option is also not visible. Is it because of the $(window).load() ?
Required Output:
Code that I am using:
jQuery(".ng-scope td.ng-binding:first-child").text(function(i, oldVal) {
return oldVal.replace(/^[^-]+ - /,"");
});
});
How can I make it so that it does not affect the <b> tag inside?
I used the above code for the steps heading with a different selector on the same page* and it worked because it did not have any children to alter.
I had to wrap it around $(window).load() so that the changes are applied after the table is loaded. $(document).ready() did not work with it. Not sure why?
(Edit: Modified to accommodate restated requirement in comment below.)
To strip "everything up to and including the '-'" from the text of first column table cells while leaving the rest untouched:
// strip "everything up to and including the '-'"
// from table cell contents
function stripPrefix(tblCell) {
// only evaluate first td in tr
if (tblCell.previousElementSibling) {
return;
}
const tNode = tblCell.firstChild;
// ignore if table cell is empty
if (!tNode) {
return;
}
const chars = tNode.nodeValue.split('');
const iFirstDash = chars.indexOf('-');
if (iFirstDash === -1) { return; }
tNode.nodeValue = chars.slice(iFirstDash+1).join('');
}
function stripAllPrefixes() {
const tds = document.getElementsByTagName('td');
for (const td of tds) {
stripPrefix(td);
}
}
td {
border: 1px solid gray;
}
<h4>Strip "everything up to and including the '-'" from Table Cells</h4>
<table>
<tr>
<td>A,B,C,D: 1 - Auswahl Wunschkarte : <b>Wähle eine Option</b></td>
<td></td>
</tr>
<tr>
<td>B,C,D,E: 20 - A different leader : <b>should also be stripped</b></td>
<td></td>
</tr>
<tr>
<td>Oops no dash here <b>Just checking</b></td>
<td></td>
</tr>
</table>
<button onclick="stripAllPrefixes();">Strip All</button>
It does not effect the b tag, your code is working, you just need to use the right method and do the replacement to the HTML code and not the text nodes:
jQuery(".nbd-field-header label, .nbo-summary-table .ng-binding").html(function(i, oldVal) {
return oldVal.replace(/^[^-]+ - /,"");
});

Protractor - How to get all cells from one column and sum them when the Grid has id="0-0" for rows-Columns

I am validating a drill down process in the portal i am testing, for this my script is doing:
Read the value from the first row of a table and click at this value (there is a link for certain cells that perform the drill down to the detail page)
To click at this particular cell I am using it's ID:
<table id="transHistTable" class="table table-hover table-bordered table-striped dataTable no-footer" style="width: 100%" role="grid" aria-describedby="transHistTable_info">
<thead>
<tbody>
<tr role="row" class="odd">
<td id="0-0" class="ng-scope">31 Jul 2018</td>
<td id="0-1" class="ng-scope">RandomText0</td>
<td id="0-2" class="ng-scope">RandomText1</td>
<td id="0-3" class="ng-scope">EmptyValue</td>
<td id="0-4" class="ng-scope">Value I Click And Save it</td>
So for this table I am clicking directly to the row 0 column 4 since my data and my filters will always bring only one row, but then, comes my problem....
When the drill down is performed I never know how many rows I will have since it depends of user operations.
I need to perform a validation to compare the sum of all the values from the table displayed after the drill down with the value captured from table "transHistTable" row 0 column 4
This is the values I get after performing the Drill Down:
<table id="transHistDetailTable" class="table table-hover table-bordered table-striped dataTable no-footer" style="width: 100%" role="grid" aria-describedby="transHistDetailTable_info">
<thead>
</thead>
<tbody><tr role="row" class="odd">
<td id="0-0" class="ng-scope">Site</td>
<td id="0-1" class="ng-scope">Date</td>
<td id="0-2" class="ng-scope">Time</td>
<td id="0-3" class="ng-scope">I</td>
<td id="0-4" class="ng-scope">value 1</td>
<td id="0-5" class="ng-scope">value 2</td>
<td id="0-6" class="ng-scope">value 3</td>
<td id="0-7" class="ng-scope">12</td>
</tr></tbody>
</table>
So what I would like to do is reading all the rows (could be 0,1,2,3,4,5...) saving the value that is stored in Column 7 then after this is done, perform a sum and then comparing with the value I have saved from the first table.
My code is this one:
var rowstransHistDetail = element(by.id('transHistDetailTable')).all(by.tagName("tr"));
rowstransHistDetail.count().then(function(rcount){
//In case only 1 row is displayed
if (rcount < 3)
{
element(by.id('0-7')).getText().then(function(valueQty){
expect(valueQty).toEqual(600)
})
}
else
{
var tempValue
for (i=0; i < rcount; i++)
{
element(by.id(i+'-7')).getText().then(function(valueQty){
tempValue = Number(tempValue) + Number(valueQty)
})
}
expect(tempValue).toEqual(600);
}
});
But when I execute this, gives me a undefined value
Any ideas how to solve this please?
Thank you!!!!
It seems that you are incrementing a value in a loop before execution.
See here: https://stackoverflow.com/a/6867907/6331748
Should bee i++ instead of ++i in a loop.
Drop me a line if I'm wrong.
===========================
Edited:
Here's some code from my side:
var expectedCells = element.all(by.css('#transHistDetailTable tr td:nth-of-type(5)'));
var currentSum = 0;
expectedCells.each((eachCell) => {
eachCell.getText().then((cellText) => {
currentSum += Number(cellText);
});
}).then(() => {
expect(currentSum).toEqual(600);
});
Sorry, but wasn't able to test it. I only want to share a main idea and elaborate it.
expectedCells are all id=n-4 cells. We go through all elements and get text from them, change to the number type and add to current value. Aftermath we do an assertion.
It also looks that if statement is not necessarily.
Let me know how it works.
Two options for your issue:
1) using element.all().reduce()
let total = element
.all(by.css('#transHistDetailTable > tbody > tr > td:nth-child(8)'))
.reduce(function(acc, item){
return item.getText().then(function(txt) {
return acc + txt.trim() * 1;
});
}, 0);
expect(total).toEqual(600);
2) using element.all().getText() and Array.reduce
let total = element
.all(by.css('#transHistDetailTable > tbody > tr > td:nth-child(8)'))
.getText(function(txts){ //txts is a string Array
return txts.reduce(function(acc, cur){
return acc + cur * 1;
}, 0);
});
expect(total).toEqual(600);

orderBy not working with pagination and filters

<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in foods | filter:foodFilter | itemsPerPage:pageSize | orderBy:'created_at_date'">
<td class="col-md-"> {{food.created_at_date}} </td>
</tbody>
</table>
<dir-pagination-controls
max-size= 7
boundary-links="true">
</dir-pagination-controls>
This is only a snippet of my code but its too large to put up. Everything is working except only some of the created_at_date is in order. When I click on a different filter to add in or remove data depending on that filter, only some of it is entered into the correct place. My main question is: is there someway to sort all of the dates properly while still allowing the everything else function as well? All help is welcome, Thanks
(function () {
"use strict";
App.controller('foodsController', ['$scope'],
function($scope) {
$scope.sortDirection = true;
In your controller you can add the method to order the array before you loop over them.
Assuming your foods array has an array of objects, each with a key of created_at_date and a value:
App.controller('foodsController', function($scope) {
$scope.foods = [{
created_at_date: 6791234
}, {
created_at_date: 9837245
}, {
created_at_date: 1234755
}];
// create a method exposed to the scope for your template.
$scope.orderBy = function(key, array) {
// now you've received the array, you can sort it on the key in question.
var sorted = array.sort(function(a, b) {
return a[key] - b[key];
});
return sorted;
}
});
Now on your template, you have a method available to sort your values for you:
<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in orderBy('created_at_date', foods) | filter:foodFilter | itemsPerPage:pageSize">
<td class="col-md-"> {{food.created_at_date}} </td>
</tr>
</tbody>
</table>
The orderBy method which we've created on your controller returns an array, but it's just sorted by the key that's sent in as the first argument of the function. The second argument is the original array you're trying to sort.
At least this way you can check if you remove all your other filters to see if it's ordered correctly, if then after you add them back in it changes it's because those filters are also changing the order.

JS DataTables ColReorder API Reorder Bug?

JS DataTables ColReorder results in unexpected behavior when using the API to re-order columns.
https://github.com/DataTables/ColReorder/
A first re-order works fine e.g.
tableColReorder.fnOrder([2, 1, 0]);
But this subsequent re-order should return columns to their original order but it doesn't. Why not?
tableColReorder.fnOrder([0, 1, 2]);
Simple fiddle example here:
http://jsfiddle.net/h7wdt72k/
$(document).ready(function () {
// Initialize data table extension.
var table = $('table')
.DataTable({
paging: false,
searching: false,
ordering: false,
bInfo: false
});
// Initialize column re-order extension.
tableColReorder = new $.fn.dataTable.ColReorder(table);
// Re-order columns. Switch first/last columns.
tableColReorder.fnOrder([2, 1, 0]);
// Re-order columns to original order 0, 1, 2. Does not work!?
tableColReorder.fnOrder([0, 1, 2]);
// Get current column order. Did not apply re-order directly above. Why not!?
alert(tableColReorder.fnOrder());
// This statement returns columns to original order 1, 2, 3. Works but why!?
//tableColReorder.fnOrder([2, 1, 0]);
});
html:
<table border="1">
<thead>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
Behavior is by design and not a bug.
//To switch position of two columns, always reorder based on array of consecutive integers (array length = number of columns).
//Even if columns already moved. Start with array of consecutive integers.
newColOrder = [0,1,2];
// Set new order of columns.
newColOrder[colTo] = colFrom; // colFrom = index to move column from.
newColOrder[colFrom] = colTo; // colTo = index to move column to.
e.g. to switch first and last column.
newColOrder[0] = 2;
newColOrder[2] = 0;
// [2,1,0];
// Reorder columns. Switch position of first and last column.
tableColReorder.fnOrder(newColOrder);
// Switch position of first and last column again. Returns columns to original position.
tableColReorder.fnOrder(newColOrder);

Sorting table rows using AngularJS

I'm just getting started with AngularJS and I'm trying to sort my table so that when a tableheader is clicked the rows are sorted per that table header.
Here is my plnkr link:
http://plnkr.co/edit/mbTq5865KKNzlvpJJy1l
Here is my relevant code:
Controller code:
$scope.setRepoSortOrder = function(order) {
if ($scope.repoSortOrder === order) {
if ($scope.repoSortOrder.charAt(0) === '+') {
order = order.replace('+', '-');
} else {
order = order.replace('-', '+');
}
}
$scope.repoSortOrder = order;
};
Table:
<table>
<thead>
<tr>
<th>Name</th>
<th>Stars</th>
<th>Language</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="repo in repos | orderBy:repoSortOrder">
<td>{{repo.name}}</td>
<td>{{repo.stargazers_count | number}}</td>
<td>{{repo.language}}</td>
</tr>
</tbody>
</table>
So when the name th is clicked the rows should be sorted by the names - same with stargazers_count and language. If a th is clicked again it should be sorted in the opposite order (if I click name first it's sorted by names in asc order - if I click it again it's sorted in desc order).
Finally: name and language should initially sort in asc order while stargazers_count should sort in desc order initially.
I've done this myself but I don't know if I'm doing it the best way possible. Since I'm not used to the "angular style" I would like to hear how people familiar with AngularJS would handle this. Please check out the plnkr link to see if you could improve it.
Any replies are appreciated!
One thing that can improve is to use a reverse flag of the orderBy filter like this:
$scope.repoSortOrder = "-stargazers_count";
$scope.isReverse = false;
$scope.setRepoSortOrder = function(order) {
$scope.isReverse = ($scope.repoSortOrder === order) ? !$scope.isReverse : false;
$scope.repoSortOrder = order;
};
Example Plunker: http://plnkr.co/edit/CM1BGkQc0AYbrraAPq8r?p=preview

Categories

Resources