Clear Row Data Based on Value in Google Sheet ( Specific Data ) appscript - javascript

I am looking for a base on value clear specific row content/data and then hide row.
type value "Done" in { F Col } Clear Value of { E , C Col }
when everything is done then hide row.
function ClearContentThenHideRow() {
var s = SpreadsheetApp.getActive().getSheetByName('Main');
s.showRows(1, s.getMaxRows());
s.getRange('F:F')
.getValues()
.forEach( function (r, i) {
if (r[0] == 'Done')
//sheet.getRange(["C:C","E:E"]).clearContent(); // clear content not working
s.hideRows(i + 1);
});
}

Modification points:
About sheet.getRange(["C:C","E:E"]).clearContent();,
sheet is not declared.
When you want to use the range list, please use getRangeList().
When s.getRange('F1:F' + s.getLastRow()) is used instead of s.getRange('F:F'), I thought that the process cost will be able to be reduced a little.
When above points are reflected to your script, it becomes as follows.
Modified script:
function ClearContentThenHideRow() {
var s = SpreadsheetApp.getActive().getSheetByName('Main');
// s.showRows(1, s.getMaxRows()); <--- removed
s.getRange('F1:F' + s.getLastRow())
.getValues()
.forEach(function (r, i) {
if (r[0] == 'Done') {
s.getRangeList(["C" + (i + 1), "E" + (i + 1)]).clearContent();
s.hideRows(i + 1);
}
});
}
Reference:
getRangeList(a1Notations) of Class Sheet

Related

How to calculate a range of cells on editing the rage in the Google Spreadsheets using Script

What I am trying to do is, whenever any cell in the range (B1:B10) is edited I want to sum up the values within the range (B1:B10) and add this to cell B11. I used the following code but it adds the formula into the cell. I want to put only the summed value, not the formula itself.
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getA1Notation() === "B1:B10" && ss.getActiveSheet().getName() == "TEST"){
ss.getActiveSheet().getRange("B11").setFormula("=SUM(B1:B10)");
}
}
I tried to find an answer on Google, but I couldn't find it.
Use Array.filter() and Array.reduce(), like this:
/**
* Simple trigger that runs each time the user hand edits the spreadsheet.
*
* #param {Object} e The onEdit() event object.
*/
function onEdit(e) {
let sheet;
if (e.range.columnStart !== 2
|| e.range.rowStart > 10
|| (sheet = e.range.getSheet()).getName() !== 'TEST') {
return;
}
const rangeToWatch = sheet.getRange('B1:B10');
const targetCell = sheet.getRange('B11');
const total = rangeToWatch.getValues()
.flat()
.filter(value => typeof value === 'number')
.reduce((sum, current) => sum + current, 0);
targetCell.setValue(total);
}
Maybe you could just get rid of the code and "hide" the formula in another cell. Let's say you need to have in A11 the text "TOTAL", then you can delete first what is in B11 and then put in A11:
={"TOTAL",SUM(B1:B10)}
This way it will expand unto B11 but if you click on that cell you'll only see the value, not the formula
PS: if you try this disable or delete the code

replacing variables of an array in a loop

I'm trying to make some sort of cryptographer, and I need to replace for ex. every "a" with "b" when the user asks for it.
if (DoYouWannaCrypt == 1) {
binput.forEach(function(v, i) {
if(v === "a") {
input[i] = "$"
}
})
};
This works fine, however I want to add another condition that this should only be done for all 5th values of another array.
if (Val is 5th) {
if (DoYouWannaCrypt == 1){
binput.forEach(function(v, i) {
if(v === "a") {
input[i] = "$"
}
})
}
};
I think you can see where I'm stuck at. I need it to work for all 5th values not just the first one.
Thats what map is for:
var crypted=binput.map((l,i)=>(i+1)%5?l:({"a":"$"}[l]||l));
http://jsbin.com/zepewituro/edit?console
Check if index (starting from 0, thats why +1 ) modulo 5 is not 0,then take the letter l, if its 0 ( then we are at the 5*n th position), then we try to replace our letter with another one, if it isnt possible fallback to the letter (||l).
Since your code appears irrelevant to your problem, let me store it safely in a function first:
function something(binput, input, DoYouWannaCrypt) {
if (DoYouWannaCrypt == 1)
binput.forEach(function(v, i) {if (v === "a") input[i] = "$"});
}
If you want to do this operation only for the first element of anotherArray:
for (let Val in anotherArray)
if (!Val) something(binput, input, DoYouWannaCrypt);
If you want to do it for every element of anotherArray:
for (let Val in anotherArray)
something(binput, input, DoYouWannaCrypt);
If you want to do it for every fifth element of anotherArray:
for (let Val in anotherArray)
if (!(Val%5)) something(binput, input, DoYouWannaCrypt);

Removing nulls from html popup

I would like to format the content of my popup so that null values are completely removed. At this point, my popup is filled with the features.properties array. There are 20 elements in properties, and depending on the queried feature, many of those values will be null.
var feature = features[0];
// Populate the popup and set its coordinates
// based on the feature found.
popup.setLngLat(feature.geometry.coordinates)
.setHTML('<div><b>' + feature.properties.city + '</div></b>' + '<div>'
+ feature.properties.course1 + '</div>' + '<div>'+
feature.properties.course2 + '<div>' + feature.properties.course3 + '</div>')
.addTo(map);
At this point, an example popup with some null values looks like this:
My aim is to eliminate null values and not to display them in the popup.
So far I've tried the JSON.stringify option instead of listing each element in separate <div> element.
function replacer(key, value) {
// Filtering out properties
if (value === "null" || value === null) {
return undefined;
}
return value;
}
JSON.stringify(feature.properties, replacer, "\t").replace(/\"/g, "").replace(/,/g, "")
This produces the desired result but then formatting is the problem.
The JSON object does not display well in a popup even when encasing it in <pre> tags, which produces:
I would like to know if there is a solution to format my popup so that it looks like the first image - but excludes null values. How can one do this is html by listing all of the property elements (course1, course2, course3, etc...) without producing a bunch of empty <div> s?
Here's one way using classic Javascript:
var features = {
properties: {
city: "Salzburg",
course1: "DCLead",
course2: "null",
course3: null,
field_1: "Hello"
}
};
function htmlFromProps(props, exclude) {
var html = "";
var i = 0;
for (p in props) {
if (props[p] && props[p] != "null" && exclude.indexOf(p) === -1) {
html += "<div>" + (i === 0 ? "<strong>" : "");
html += props[p];
html += (i++ === 0 ? "</strong>" : "") + "</div>\n";
}
}
return html;
}
popup.innerHTML = htmlFromProps(features.properties, ["field_1"]);
#popup {
width: 80%
}
<textarea id="popup"></textarea>
Use it by calling .setHTML(htmlFromProps(features.properties, [])) where the second argument is an array of fields you want to exclude.
You could try filtering your properties, see the example below:
var feature = {
properties: {
city: 'Salzburg',
course1: 'test',
course3: 'test3'
}
};
var html = Object
.keys(feature.properties)
.map(key => feature.properties[key])
.filter(value => value)
.map((value, i) => i === 0
? `<div><strong>${value}</strong></div>`
: `<div>${value}</div>`
)
console.log(html);
The crucial part is .filter(value => value) where filter makes sure that only truthy (non-null) values remain in the array.

Number value wrong in event bound through a for loop

var rows = document.getElementsByClassName('row');
for (var i = 0, l = rows.length; i < l; i++) {
if (i % 2 === 0) {
$(rows[i]).click(function () {
alert('I am line number ' + i);
}
}
}
Hi,
how would I get actual line number for each row ? since all I get when I trigger click event on an even row, upper bound value is alerted (i.e: rows.length = 7, i would be 6 for each row clicked).
The problem is that upon click event is triggered, the i variable was already changed by the loop iteration. Theoretically you can use closure to make things working, i.e.
for (var i = 0, l = rows.length; i < l; i++) {
if (i % 2 === 0) {
(function(i) {
$(rows[i]).click(function() {
alert("I am line number " + i);
});
)(i);
}
}
Practically, if you use jQuery (as I understood from the code), it is easier to use :even selector:
$(".row:even").click(function() {
alert("I am line number " + $(".row").index(this));
});
The reason you're getting the wrong number is that the event handler functions you're creating get an enduring reference to the i variable, not a copy of it as of when they're created.
The way to solve it is to have the handler close over something that won't change. Here are three ways to do that, the first is specific to jQuery (it looks like you're using jQuery):
jQuery's each
It looks like you're using jQuery, in which case you can use its each to get an index to use that won't change:
var rows = $(".row");
rows.each(function(index) {
if (index % 2 === 0) {
$(this).click(function() {
alert('I am line number ' + index);
});
}
});
Now, the event handler function closes over the index argument of the call to the function we give each, and since that index argument never changes, you see the right number in the alert.
Use a builder function
(Non-jQuery) You can solve this with a builder function:
var rows = document.getElementsByClassName('row');
for (var i = 0, l = rows.length; i < l; i++) {
if (i % 2 === 0) {
$(rows[i]).click(buildHandler(i));
}
}
function buildHandler(index) {
return function () {
alert('I am line number ' + index);
};
}
Here, the event handler function closes over the index argument in buildHandler, and since that index argument never changes, you see the right number in the alert.
forEach
(Non-jQuery) You can also use ES5's forEach function (which is one of the ES5 features you can shim on a pre-ES5 environment) to solve this:
var rows = document.getElementsByClassName('row');
Array.prototype.forEach.call(rows, function(row, index) {
if (index % 2 === 0) {
$(row).click(function () {
alert('I am line number ' + index);
});
}
});
This works the same way as the two above, by closing over index, which doesn't change.

How to stop the table from being built again

I've got a lovely table function from josh.trow # link that builds a 4x4 table which can be filled with color. The only problem is is that it rebuilds itself every time I call the function (hence the first time I call the file I see a 4x4 table, the second time I see a 8x4 table, and so on.) It doesn't multiply the rows because they are already limited to 4.
I can't see what check I need to put in that limits the table's columns to only being built once. (4)
Here's the JS code:
function repeatedFunction(L, G, P, D) {
jQuery.fn.reverse = [].reverse;
var completeData = [L, G, P, D];
var max = 4;
$.each(completeData, function(intIndex, objValue) {
if (objValue > max) max = objValue;
});
for (var i = 0; i < max; i++)
{
$('#statSheetTable').append('<tr id="resultRow' + i + '"></tr>');
$.each(completeData, function(intIndex, objValue) {
$('#resultRow' + i).append('<td name="column' + intIndex + '" ></td>');
});
}
$.each(completeData, function(intIndex, objValue) {
$('td[name=column' + intIndex + ']').reverse().each(function(idx, val) {
if (idx < objValue) $(this).addClass('complete' + intIndex);
});
});
}
I tried using a global variable, which stopped the table from being duplicated, but then my color filling code was not functioning (as it can't be refreshed with the new instructions to fill with color).
Essentially what I added to the above function was:
var firstTime = true;
.....
function repeatedFunction(L, G, P, D, 4) {
if(firstTime == true)
{
.....
// code from above block
.....
firstTime = false;
}
Do your experienced JS eyes see where I can limit the table from building more columns?
Here you go chief, updated as you asked.
EDIT: Whoops, now it works :)
http://jsfiddle.net/X83ya/2/
First, always use identical comparison operators when comparing boolean values:
if(firstTime === true)
That being said, you don't need it if you just want to rebuild your table. $('#statSheetTable').append(... will just "add to" whatever was in there. Make sure you clear it out in the beginning like such:
...
var max = 0;
$('#statSheetTable').html('');
...

Categories

Resources