Angular table sorting - angularjs

I need to sort table items by clicking table header. My column values number as string. So sorting is not applying as I wish. I know I should convert my string into float. I need comma separator and double point precision as well. I tried to do parseFloat but that's not working.
Example. I want to sort "123,456.00", "345", "-34.00", "7.78" kind of strings. I shared jsfiddle link to explain my scenario.
http://jsfiddle.net/k4seL1yx/1/
function SortableTableCtrl() {
var scope = this;
scope.head = {
a: "Poured",
b: "Sold",
c: "Loss"
};
scope.body = [{"ID":"September-2016", "Product":"September-2016", "Poured":"111759.07", "Sold":"107660.97", "Loss":"-4098.10", "Variance":"-3.67", "startDate":"2016-09-01", "endDate":"2016-09-22"}, {"ID":"November-2015", "Product":"November-2015", "Poured":"53690.25", "Sold":"52953.60", "Loss":"-736.65", "Variance":"-1.37", "startDate":"2015-11-20", "endDate":"2015-11-30"}, {"ID":"May-2016", "Product":"May-2016", "Poured":"156401.65", "Sold":"151192.51", "Loss":"-5209.14", "Variance":"-3.33", "startDate":"2016-05-03", "endDate":"2016-05-31"}, {"ID":"March-2016", "Product":"March-2016", "Poured":"49260.22", "Sold":"49399.14", "Loss":"138.92", "Variance":"0.28", "startDate":"2016-03-01", "endDate":"2016-03-09"}, {"ID":"June-2016", "Product":"June-2016", "Poured":"162126.88", "Sold":"161718.62", "Loss":"-408.26", "Variance":"-0.25", "startDate":"2016-06-01", "endDate":"2016-06-30"}, {"ID":"July-2016", "Product":"July-2016", "Poured":"160185.68", "Sold":"154882.40", "Loss":"-5303.28", "Variance":"-3.31", "startDate":"2016-07-01", "endDate":"2016-07-31"}, {"ID":"January-2016", "Product":"January-2016", "Poured":"355509.26", "Sold":"179696.72", "Loss":"-175812.54", "Variance":"-49.45", "startDate":"2016-01-01", "endDate":"2016-01-31"}, {"ID":"February-2016", "Product":"February-2016", "Poured":"150980.73", "Sold":"146248.72", "Loss":"-4732.01", "Variance":"-3.13", "startDate":"2016-02-01", "endDate":"2016-02-29"}, {"ID":"December-2015", "Product":"December-2015", "Poured":"167843.42", "Sold":"163732.95", "Loss":"-4110.47", "Variance":"-2.45", "startDate":"2015-12-01", "endDate":"2015-12-31"}, {"ID":"August-2016", "Product":"August-2016", "Poured":"168853.51", "Sold":"160024.84", "Loss":"-8828.67", "Variance":"-5.23", "startDate":"2016-08-01", "endDate":"2016-08-31"}]
scope.sort = {
column: 'b',
descending: false
};
scope.selectedCls = function(column) {
return column == scope.sort.column && 'sort-' + scope.sort.descending;
};
scope.changeSorting = function(column) {
var sort = scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
};
}

I found a solution for my question. Actually I am very focused on convert "poured, sold, loss" from string to float. But why I should not create a new column as clone of this and the format of that is float. parseFloat done the magic. So I can use Poured value for table show and use pouredClone value for sorting on the behind.
//Initially I got the above scope.body only. To perform sorting I modified scope.body as like below
scope.body.forEach(function(value) {
value.pouredClone = parseFloat(value.Poured)
value.soldClone = parseFloat(value.Sold)
value.lossClone = parseFloat(value.Loss)
value.varianceClone = parseFloat(value.Variance)
});
Here is the link of fiddle with solution.
http://jsfiddle.net/q7mcu6fx/1/

Related

Is there a way to exclude cells that contain formulas from my Google Script?

Apologies is this has been asked already but if someone could point me in the right direction that would be great. I've looked for several versions/solutions to this but can't seem to find one (I may be looking in the wrong place).
Basically, I'm looking for a way to exclude any cells that contain a formula from the following script. So I only want it to run this on cells that exactmatch "1". Any help would be greatly appreciated.
function runReplaceInSheet(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2020");
// get the current data range values as an array
var values = sheet.getDataRange().getValues();
// Replace 1 with HOL
replaceInSheet(values, "1", "HOL");
// Write all updated values to the sheet, at once
sheet.getDataRange().setValues(values);
}
function replaceInSheet(values, to_replace, replace_with) {
//loop over the rows in the array
for(var row in values){
//use Array.map to execute a replace call on each of the cells in the row.
var replaced_values = values[row].map(function(original_value) {
return original_value.toString().replace(to_replace,replace_with);
});
//replace the original row values with the replaced values
values[row] = replaced_values;
}
}
Flow:
getFormulas and replace only if the array of formulas is empty
Sample script:
function replace(sheetName = '2020', searchValue = '1', replaceValue = 'HOL') {
const sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
const range = sheet.getDataRange();
const formulas = range.getFormulas();
const values = range.getValues();
range.setValues(
formulas.map((row, i) =>
row.map(
(formula, j) =>
formula || values[i][j].toString().replace(searchValue, replaceValue)
)
)
);
}
You may use the getFormulas() method to get all the formulas in the current shet and iterate through them like a 2d array.
var values = sheet.getDataRange().getDisplayValues();
var formulas = sheet.getDataRange().getFormulas();
for (var r=0; r<values.length; r++) {
for (var c=0; c<values[r].length; c++) {
var cellValue = values[r][c];
var formula = formulas[r][c];
if (!formula && cellValue === "1") {
sheet.getRange(r+1, c+1).setValue("HOL")
}
}
}

use ISFORMULA with ARRAYFORMULA on a range of cells

I have a row of cells, some with a formula, and some without.
I am trying to use ARRAYFORMULA WITH IFFORMULA to see if a cell has a formula or not. This is the function I am using:
=ARRAYFORMULA(ISFORMULA(B2:B))
But it just outputs one single value.
There are other things I need to do for each row/cell which is why I need ARRAYFORMULA.
Is there another way to get ISFORMULA to work with ARRAYFORMULA?
not all functions are convertible into ArrayFormula. ISFORMULA is one of those...
the best you can do is pre-program it like:
={ISFORMULA(B2);
ISFORMULA(B3);
ISFORMULA(B4);
ISFORMULA(B5);
ISFORMULA(B6)}
the next best thing you can do is to use conditional formatting to color it like:
green color:
=ISFORMULA($B2)
red color:
=NOT(ISFORMULA($B2))*(B2<>"")
UPDATE
now possible with lambda:
=BYROW(B2:B6; LAMBDA(x; ISFORMULA(x)))
This is so frustrating. I myself have made areFormula() by my needs. Not so elegant, but working. It takes a range of row or column (if area, treated as a row), and returns a row.
function areFormula(rowOrColumn) {
// takes a range as input parameter
// from https://webapps.stackexchange.com/a/92156
var sheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var args = formula.match(/=\w+\((.*)\)/i)[1].split('!');
try {
if (args.length == 1) {
var range = sheet.getRange(args[0]);
}
else {
sheet = ss.getSheetByName(args[0].replace(/'/g, ''));
range = sheet.getRange(args[1]);
}
}
catch(e) {
throw new Error(args.join('!') + ' is not a valid range');
}
rowOrColumn = range;
//here starts my code
let values = rowOrColumn.getValues();
let isItRow = true;
if(values.length == 1) {
isItRow = false;
values = values[0];
}
else {
values = values.map(el => el[0]);
}
let result = [];
let x = 0, y = 0;
for(let i = 0; i < values.length; i++) {
const cell = rowOrColumn.getCell(1+y, 1+x);
result.push(cell.getFormula() ? true : false);
if(isItRow)
y++;
else
x++;
}
console.log(result);
return(result);
}

AngularJS mysql filter multiple element

Hi this is my hotel project. But I'm having a problem with a filter.
I want to filter the data in the amenities column.
This is: my fiddle
It works if you select a single checkbox but it does not work if you select multiple checkboxes.
I suspect the problem arises from indexof instead of what I can use. What method should I follow?
How to change this line: indexOf(x);
This is my bad code:
//PROBLEM FILTER HERE
$scope.am_en = function()
{
//get input value
x = $(".hosting_amenities input:checkbox:checked").map(function(){return $(this).val();}).get();
//filter
$scope.ot_Filter = function (location) {
return location.amenities.indexOf(x) !== -1;
};
}
The problem is indeed caused by the function $scope.am_en, in the declaration of the inner function $scope.ot_Filter
When you select multiple checkboxes, your x variable is an array of objects, so you should do a loop and can create a variable to check whether the element should be shown or not. You can do it as follows:
$scope.ot_Filter = function (location) {
var shouldBeShown = false;
for (var i = 0; i < x.length; i++) {
if (location.amenities.indexOf(x[i]) !== -1) {
shouldBeShown = true;
break;
}
}
return shouldBeShown;
};
I modified your jsfiddle, so that you can see this solution working properly.

protractor -- Copy the column elements to array , sort it and compare the first array element with the first column data

I am trying to copy a column of UI grid elements to an array and sort it and compare the first element of array with the first column data to check the UI grid column data is sorted correctly.
This is my code --
I get the error - unsorted.then is not a function. Can you please help me. also let me know if i can use any other method.
thanks in advance.
var rows = element(by.id('grid2')).element( by.css('.ui-grid-render-container-body')).all( by.repeater('(rowRenderIndex, row) in rowContainer.renderedRows track by $index'));
var results = [];
var res = rows.count().then(function(cnt){
console.log('inside loop');
console.log(cnt);
for(i=0; i < cnt; i++){
ele = test.datacell('grid2',i,0);
ele.getText().then(function(txt){
console.log(txt);
results.push(txt);
});
}
var unsorted = results.map(function(element) {
console.log(element.getText());
return element.getText();
});
var sorted = unsorted.then(function(texts) {
return texts.slice(0).sort();
});
ele = cmn.datacell('grid1',0,colcount);
expect(ele.getText()).toEqual(sorted[0]);
for sorting in descending order you could use try this -
var sorted = unsorted.then(function(texts) {
return texts.slice(0).sort(function (a,b) {
return b-a;
});
});

Sorting an array by its nth-grand-child

I want to extend the functionality of this function AngularJS sorting by property.
It basically sorts an array by its child property. But what I want is to make it more generalized, to make it able to sort by any specified nth-grand-child.
The function is
function orderObjectBy(input, attribute) {
if (!angular.isObject(input)) return input;
var array = [];
for(var objectKey in input) {
array.push(input[objectKey]);
}
array.sort(function(a, b){
a = parseInt(a[attribute]);
b = parseInt(b[attribute]);
return a - b;
});
return array;
}
Here's an array which works with this: orderObjectBy(object, 'stat_a')
array = [
{stat_a:3},
{stat_a:2},
{stat_a:5},
]
Here's what I want to work with it: orderObjectBy(object, 'stats.a')
array = [
{stats:{a: 3}},
{stats:{a: 2}},
{stats:{a: 5}},
]
I have no idea how to do it though. The line where it compares
a = parseInt(a[attribute]);
cannot just take stats.a as attribute.
Neither could I figure out how to make it parseInt(a[stats][a])
Note, stats.a example would be merely .split('.').pop() etc but I want a more general approach, that'll work for stats.some.things.a or stats.some.other.things.a ...)
Any guidance how to proceed?
Split the attribute name by "." and explore the object with the attribute name list.
array.sort(function(a,b) {
a = parseInt(getAttribute(a, attribute);
b = parseInt(getAttribute(b, attribute);
return a-b
})
function getAttribute(object,attribute) {
var o = object;
var attrs = attribute.split(".")
for ( var i=0; i<attrs.length; i++) {
o = o[attrs[i]];
if (o==null) {
return null;
}
}
return o;
}

Resources