Please help me modify below script. I have a list of links to Google Spreadsheets in column A. I need to put in column B opposite each link the number of open (unresolved) comments.
I'm just starting to learn Google script and I can't do it.
function listComments() {
// Change docId into your document's ID
var docId = 'docId';
var comments = Drive.Comments.list(docId);
var hList = [], cList = [], dList = [];
if (comments.items && comments.items.length > 0) {
for (var i = 0; i < comments.items.length; i++) {
var comment = comments.items[i];
hList.unshift([comment.context.value]);
cList.unshift([comment.content]);
dList.unshift([comment.status]);
}
// // Set values to A and B
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange("A1:A" + hList.length).setValues(hList);
sheet.getRange("B1:B" + cList.length).setValues(cList);
sheet.getRange("C1:C" + cList.length).setValues(dList);
}
}
Related
I have a program that filters and updates data from an existing sheet.
The program works as follows:
1. Find and filter out the required value
2. Enter data in [Adjustment] column then update to database in Record sheet.
I tried to try but my program doesn't seem to work.
I tried to edit the program code but when run it will affect the other columns and the [adjustment] column value is entered wrong.
This is my link program
function Searchold(){
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var shtRecords = ss. getSheetByName ("RECORD");
var shtForm = ss. getSheetByName ("TEST") ;
var records = shtRecords. getDataRange () . getValues ();
var sField = shtForm. getRange ("A3").getValue ();
var sValue = shtForm.getRange ("A6").getValue();
var sCol = records [0].lastIndexOf(sField);
var results = records.filter(function(e){return sValue == e[sCol] });
if(results.length==0){SpreadsheetApp.getUi().alert("not found values");}
else{
shtForm.getRange(9,1,results.length,results[0].length).setValues(results);
}
}
function Updatenew(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var shtRecords = ss.getSheetByName("RECORD");
var shtForm = ss.getSheetByName("TEST");
var LastRow = shtForm.getRange("A8").getNextDataCell(SpreadsheetApp.Direction.DOWN).getLastRow();
var newData = shtForm.getRange(9,1,LastRow -1,7).getValues();
for(var i =0; i<newData.length;i++){
var oldData= shtRecords.getDataRange().getValues();
for(var j= 0;j<oldData.length;j++){
if(newData[i][0] ==oldData[j][0]){
var newData2 = [newData[i]];
shtRecords.getRange(j + 1,1,1,newData2[0].length).setValues(newData2);
}
}
}
}
Can you help me with the update program? Sincerely thank you
Modification points:
When I saw your showing script of Updatenew, I think that each row of var oldData = shtRecords.getDataRange().getValues() is used in each loop of for (var i = 0; i < newData.length; i++) {}. By this, each row is overwritten by each row of newData. By this, all searched rows in "RECORD" sheet are the same value. I thought that this might be the reason for your issue.
var oldData = shtRecords.getDataRange().getValues(); can be used one call.
In order to avoid this issue by modifying your script, as one of several methods, how about the following modification?
From:
for (var i = 0; i < newData.length; i++) {
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
if (newData[i][0] == oldData[j][0]) {
var newData2 = [newData[i]];
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
}
}
}
To:
var oldData = shtRecords.getDataRange().getValues();
for (var j = 0; j < oldData.length; j++) {
for (var i = 0; i < newData.length; i++) {
if (newData[0][0] == oldData[j][0]) {
var newData2 = newData.splice(0, 1);
shtRecords.getRange(j + 1, 1, 1, newData2[0].length).setValues(newData2);
break;
}
}
}
Note:
At the above modification, setValues is used in a loop. In this case, the process cost becomes high. If you want to reduce the process cost of the script, how about using Sheets API? When Sheets API is used, how about the following modification? Please enable Sheets API at Advanced Google services.
To
var temp = newData.slice();
var data = shtRecords.getDataRange().getValues().reduce((ar, r, i) => {
if (temp[0][0] == r[0]) {
var t = temp.splice(0, 1);
t[0][2] = Utilities.formatDate(t[0][2], Session.getScriptTimeZone(), "dd/MM/yyyy");
t[0][4] = Utilities.formatDate(t[0][4], Session.getScriptTimeZone(), "dd/MM/yyyy");
ar.push({ range: `'RECORD'!A${i + 1}`, values: t });
}
return ar;
}, []);
Sheets.Spreadsheets.Values.batchUpdate({ data, valueInputOption: "USER_ENTERED" }, ss.getId());
Is there a way to get the current editors of a cell without having to first set permissions? The code I have below resets the permissions to the sheet default and then grabs that as the current editors as opposed to using the editors that were there before overwriting that cell with protect().
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var name = sheet.getRange("A4:A52").getValues();
var setPermissions = [];
//Employee preferred initials in order to match last name array
var initialsToMatchLastName = ['CC','RR'];
//Employee last names
var lastNames = ['Charles','Rickey'];
var emails = ['charles#email.com','rickey#email.com'];
name.forEach((value,v) => {
for (var i = 0; i < lastNames.length; i++) {
if (value[0] == lastNames[i]) {
var protection = sheet.getRange("R" + (v + 4)).protect().setDescription('Locked_' + lastNames[i] + '_' + v);
var users = protection.getEditors();
//Logger.log(users);
//Logger.log(emails[i]);
if (users.includes(emails[i])) {
//Do nothing.
} else {
protection.removeEditors(users);
protection.addEditor(emails[i]);
}
}
}
})
}
I have "script A" that can list of any file in "source folder" with url
Then i write "script B" to scan all ID of them and get every email user of file's permission, but when i set "email" value to [i] rows, it will overwrite till the last user of that permission.
Examples: if file "A" has 3 users of view, a#gmail, b#gmail, c#gmail, then "script B" will overwrite till c#gmail at file "A" row. (then we dont know about a#gmail, b#gmail have viewer permission.)
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength(); var data = getSheetValues();
for(var i = 0; i < dataLength; i++) {
if(data[i]["Condition"] != "1") continue
var thisid = SpreadsheetApp.getActiveSheet().getRange(i+1, 12).getValue()
Logger.log(thisid)
var editors = DriveApp.getFileById(thisid).getEditors()
for (var x = 0; x < editors.length;x++){
var edit = editors[x].getEmail() }
SpreadsheetApp.getActiveSheet().getRange(i+1, 14).setValue(edit)
var viewers = DriveApp.getFileById(thisid).getViewers()
for (var x = 0; x < viewers.length;x++) {
var view = viewers[x].getEmail()
Logger.log(view)
SpreadsheetApp.getActiveSheet().getRange(i+1, 13).setValue(view)
}}}
This is log of runing script, in the red box, there are 2 user of view but it overwrite at: Range(i+1,13)
Any idea to solve this isue, thank you very much.
You want to retrieve emails of editors and viewers from the file ID.
File IDs are in the column "L".
You want to put the retrieved values to the cells.
From your script, I thought that you might want to put the values of editors and viewers to a cell, respectively.
You want to put the viewers and editors to the column "M" and "N", respectively.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about creating a value using join() and putting the value to the cells? For this situation, how about the following modifications? Please think of this as just one of several answers.
Modified script 1:
Please modify your script as follows. In this modification, the for loop is modified.
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength();
var data = getSheetValues();
for(var i = 0; i < dataLength; i++) {
if (data[i]["Condition"] != "1") continue
var thisid = ss.getRange(i+1, 12).getValue()
var editors = DriveApp.getFileById(thisid).getEditors()
var edit = [];
for (var x = 0; x < editors.length;x++) {
edit.push(editors[x].getEmail());
}
ss.getRange(i+1, 14).setValue(edit.join(","));
var viewers = DriveApp.getFileById(thisid).getViewers();
var view = [];
for (var x = 0; x < viewers.length;x++) {
view.push(viewers[x].getEmail());
}
ss.getRange(i+1, 13).setValue(view.join(","));
}
}
Modified script 2:
Please modify your script as follows. In this modification, the values are retrieved by getValues() and are created in the for loop and the created values are put to the Spreadsheet using setValues(). I think that this becomes lower cost of the process than that of getValue() and setValue().
function Listpermission() {
var ss = SpreadsheetApp.getActiveSheet();
var dataLength = getDataLength();
var data = getSheetValues();
var thisids = ss.getRange(1, 12, dataLength, 1).getValues();
var values = [];
for (var i = 0; i < thisids.length; i++) {
if (data[i]["Condition"] != "1") {
values.push(["", ""]);
continue;
}
var thisid = thisids[i][0];
var view = [];
var viewers = DriveApp.getFileById(thisid).getViewers();
for (var x = 0; x < viewers.length;x++) {
view.push(viewers[x].getEmail());
}
var edit = [];
var editors = DriveApp.getFileById(thisid).getEditors();
for (var x = 0; x < editors.length;x++) {
edit.push(editors[x].getEmail());
}
values.push([view.join(","), edit.join(",")]);
}
ss.getRange(1, 13, values.length, 2).setValues(values);
}
References:
join()
getValue()
setValue(value)
getValues()
setValues(values)
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
If I misunderstood your question and this was not the result you want, I apologize.
Fill array with all values to Array and then join all values to one column.
var viewers = DriveApp.getFileById(thisid).getViewers();
var viewerEmails = [];
for (var x = 0; x < viewers.length;x++) {
var view = viewers[x].getEmail();
Logger.log(view);
viewerEmails.push(view);
}
SpreadsheetApp.getActiveSheet().getRange(i+1, 13).setValue(viewerEmails.join());
The code provided copies data from sheet "Feuille 3" to an another sheet named "INITIALE". Some of the rows in the source sheet tab, "Feuille 3" are hidden.
I hide some rows in "Feuille 3" when col D has a checkbox with a "true" value.
I don't know how I can check the rows hidden in "Feuille 3" and remove these rows in my array "Nouvelleliste."
Here is the code :
function copiertableau() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var orig = ss.getSheetByName("Feuille 3");
var dest = ss.getSheetByName("INITIALE");
var Ancienneliste = orig.getDataRange().getValues();
var Nouvelleliste = new Array();
for (var i = 0; i < Ancienneliste.length; i++) {
var Nouvelleligne = new Array();
for (var j = 0; j < 3; j++) {
Nouvelleligne[j] = Ancienneliste[i][j];
}
Nouvelleliste[i] = Nouvelleligne;
}
ss.getSheetByName("INITIALE").getRange(22, 1, Nouvelleliste.length, 3).setValues(Nouvelleliste);
SpreadsheetApp.flush();
}
The Advanced Sheets API has a way of finding all the rows that were hidden by the user or by code. You must explicitly enable the Advanced Sheets API from the code editor. From the code editor choose, "Resources" and "Advanced Google Services." Scroll down to "Google Sheets API" Turn the button ON. Then click the link to Google API Console. Enable the Google Sheets API in your console.
First get all the rows that are hidden. In the example below, that is done in a separate function. Then compare the current row index to the values in the array. If there is a hidden row, then don't put the row's data into the array.
function copiertableau() {
var arrOfHiddenRows,Nouvelleligne,o,sourceSheetTab,ss;
ss = SpreadsheetApp.getActiveSpreadsheet();
sourceSheetTab = ss.getSheetByName("Feuille 3");
var dest = ss.getSheetByName("INITIALE");
sourceSheetTab = ss.getSheetByName("INITIALE");
var Ancienneliste = sourceSheet.getDataRange().getValues();
var Nouvelleliste = [];
o = {};//Object for arguments to pass to function to get the hidden rows
o.L = sourceSheetTab.getLastRow();
o.ssID = ss.getId();//Put the spreadsheet file ID into the object with key name ssID
o.sheetId = sourceSheetTab.getSheetId();
arrOfHiddenRows = getRowsHiddenByUsr(o);//Get a list of all hidden rows in sheet tab sourceSheet
//Logger.log('arrOfHiddenRows: ' + arrOfHiddenRows)
for (var i = 0; i < Ancienneliste.length; i++) {
if (arrOfHiddenRows.indexOf(i+1) !== -1) {//This row is hidden in the sheet sourceSheet
continue;//continue to loop without putting this rows data into the array
}
Nouvelleligne = [];
for (var j = 0; j < 3; j++) {
Nouvelleligne[j] = Ancienneliste[i][j];
}
Nouvelleliste[i] = Nouvelleligne;
}
ss.getSheetByName("INITIALE").getRange(22, 1, Nouvelleliste.length, 3).setValues(Nouvelleliste);
SpreadsheetApp.flush();
}
function getRowsHiddenByUsr(po) {
try{
var arrHiddenRows,data,fields,i,j,L,L_sh,rows,sheets,sheetId,spreadsheetId,thisSheet,thisShID;
/*
po.L - row length of the sheet tab
po.ssID - the spreadsheet file ID of the spreadsheet
po.sheetID - The ID of the sheet tab
*/
L = po.L;
spreadsheetId = po.ssID;
sheetId = po.sheetID;
//Logger.log(L)
//Logger.log('sheetId: ' + sheetId)
arrHiddenRows = [];
fields = "sheets(data(rowMetadata(hiddenByUser)),properties/sheetId)";//Get only metadata of hidden rows by user
sheets = Sheets.Spreadsheets.get(spreadsheetId, {fields: fields}).sheets;
L_sh = sheets.length;
//Sheets.Spreadsheets.get(spreadsheetId)
//Logger.log('sheets.length: ' + sheets.length)
for (i = 0; i < L_sh; i++) {
thisSheet = sheets[i];
//Logger.log('thisSheet === undefined: ' + thisSheet === undefined)
if (thisSheet === undefined) {
continue;
}
thisShID = thisSheet.properties.sheetId;
//Logger.log('thisShID: ' + thisShID)
if (thisShID === sheetId) {
//Logger.log('they are equal')
data = thisSheet.data;
rows = data[0].rowMetadata;
//Logger.log('thisShID: ' + thisShID)
//Logger.log('rows.length: ' + rows.length)
for (j = 0; j < L; j++) {
//Logger.log(rows[j].hiddenByUser)
if (rows[j].hiddenByUser) arrHiddenRows.push(j+1);
}
}
}
return arrHiddenRows;
}catch(e) {
console.log(e.message);
console.log(e.stack);//log the stack
}
}
thanks #SandyGood It seems it's missing something.
Firstly, i changed
var Ancienneliste = sourceSheet.getDataRange().getValues();
to put "sourceSheetTab" variable; and i delete a line because you put twice "sourceSheetTab" with 2 contents so i keep the first one.
Secondly, your function continue to copy hidden rows in the sourcesheet table.
maybe i can put my other code i did to hide rows in "Feuille 3" to help?
//global variables
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Feuille 3");
function cacherRow() {
for (var i=1; i < 300; i ++){
var nb = sheet.getRange('D'+i).getValue();
if (nb == true){
sheet.hideRows(i);
}
}
}
i enable googlesheets API in the console.
Google Apps Script now offers a new method - isRowHiddenByUser - to determine if a particular row is hidden or not.
for (var i = 0; i < Ancienneliste.length; i++) {
if (sheet.isRowHiddenByUser(i+1)) {
// do something
}
}
Note that you need to specify the row position in the method and it begins from 1, not 0.
Click here for Sample Sheet
I need a solution that matches a cell value (Sheet1! Q5) to a range in another tab/sheet (NegotiationData! A1:O1) and paste the relevant data fetched from the first sheet under the designated columns of the second sheet under the matched value.
For example, if Sheet1!Q5 matches with the name in NegotiationData! A1 then do the following
Fetch Sheet1! R6 and paste in NegotiationData!A3:A
Fetch Sheet1! Q6 and paste in NegotiationData!B3:B
Fetch Sheet1! Q7 and paste in NegotiationData!C3:C
Also, each time the script runs it should not overwrite data but find the next empty row and paste the values.
I have an incomplete script that I'm trying to achieve the above from my research from various posts but since I'm just a week old to coding I'm not able to go any further than where I have got with the below script.
I'm not finding how to match the value and fetch the relevant data and paste them below the matched value.
Please help!
The Incomplete / Incorrect Script (File Name: NegotiationSubmit)
function submitNegotiation() {
var sh, id, v, estNum, negotiation, negoNotes, i;
sh = SpreadsheetApp.getActive();
id = sh.getSheetByName('Sheet1').getRange('Q5').getValue();
v = sh.getRange('R6').getValue();
estNum = Number(sh.getRange('Q6').getValue().split(" ")[1]);
negoNotes = sh.getRange('Q7').getValue();
negotiation =sh.getSheetByName('NegotiationData').getRange('A1:O');
if(v && estNum) {
negotiation.setValues(negotiation.getValues()
.map(function (r, i) {
if (r[0] == id) {
r[1] = v;
r[2] = estNum;
r[3] = negoNotes;
}
return r;
})
)
}
}
How about this modification?
Modification points :
Retrieve values of "Q5:R7" at once, and the values are converted to the import values.
Use the destructuring assignment for retrieving each value.
Import the converted values using the number of column retrieved by ids[0][i] == id.
Modified script :
function submitNegotiation() {
var id, estNum, v, negoNotes;
var sh = SpreadsheetApp.getActive();
var values = sh.getSheetByName('Sheet1').getRange("Q5:R7").getValues();
[id] = values[0];
[estNum, v] = values[1];
[negoNotes] = values[2];
// estNum = Number(estNum.split(" ")[1]); // If you want to use "estNum = Number(sh.getRange('Q6').getValue().split(" ")[1]);", please use this line.
var sh2 = sh.getSheetByName('NegotiationData');
var ids = sh2.getRange("A1:O1").getValues();
for (var i=0; i<ids[0].length; i++) {
if (ids[0][i] == id) {
sh2.getRange(sh2.getLastRow() + 1, i + 1, 1, 3).setValues([[v, estNum, negoNotes]]);
}
}
}
Note :
I was confused to the following points.
In your script, estNum is Number(sh.getRange('Q6').getValue().split(" ")[1]);. But in your sample spreadsheet, Estimate 1 of cell "Q6" is used.
I commented this in modified script.
In your sample spreadsheet, "Story ID" is 1. But in your script, it's US-001 of cell "R6".
In this modified script, US-001 of cell "R6" was used.
If I misunderstand your question, I'm sorry.
Edit :
function submitNegotiation() {
var id, estNum, v, negoNotes;
var sh = SpreadsheetApp.getActive();
var values = sh.getSheetByName('Sheet1').getRange("Q5:R7").getValues();
[id] = values[0];
[estNum, v] = values[1];
[negoNotes] = values[2];
estNum = Number(estNum.split(" ")[1]); // If you want to use "estNum = Number(sh.getRange('Q6').getValue().split(" ")[1]);", please use this line.
var sh2 = sh.getSheetByName('NegotiationData');
var ids = sh2.getRange("A1:O1").getValues();
for (var i=0; i<ids[0].length; i++) {
if (ids[0][i] == id) {
var temp = sh2.getRange(1, i + 1, sh2.getLastRow(), 3).getValues();
for (var j=temp.length-1; j>=0; j--) {
if (temp[j].join("") != "") {
sh2.getRange(j + 2, i + 1, 1, 3).setValues([[v, estNum, negoNotes]]);
break;
}
}
}
}
}
I realize that this does not resemble your code. Sorry about that. I'm learning too. But I'm putting it up anyway to provide an alternative method that includes finding the last row of the appropriate column...
function submitNegotiation() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName('Sheet1');
var negotiationData = ss.getSheetByName('NegotiationData');
// Sheet1 variables
var user = sheet1.getRange('Q5').getValue();
var storyId = Number(sheet1.getRange('R6').getValue().split("-")[1]);
var estimateNum = sheet1.getRange('Q6').getValue();
var note = sheet1.getRange('Q7').getValue();
var pointers = [storyId, estimateNum, note];
// NegotiationData variables
var range = negotiationData.getDataRange().getValues();
var columns = negotiationData.getLastColumn();
var users = negotiationData.getRange(1, 1, 1, columns).getValues();
for(var i = 0; i < columns; i++) {
// match user with users to get column number
if(users[0][i] == user) {
var col = negotiationData.getRange(1, i + 1).getColumn();
// count rows in col
var rowCount = 1;
for(var i = 1; i < range.length; i++) {
if (range[i][col - 1] != "") {
rowCount++;
}
}
// assign pointers
var newRow = rowCount + 1;
for(var j = 0; j < pointers.length; j++) {
negotiationData.getRange(newRow, col, 1, 1).setValue(pointers[j]);
col++;
}
}
}
}