Angular material table change pagination format - angular-material

I am trying to implement an angular material table. I am able to show the table with data and pagination.
But currently the pagination format displaying is in the format below.
Items per page 10 1- 10 of 20
But I want the pagination format to be like this.
Items per page 10 Range: 10/20
Here is the plnkr URL.

1.Create a customIntl extends MatPaginatorIntl.You can replace lables of you own.
import { MatPaginatorIntl } from '#angular/material';
export class CustomMatPaginatorIntl extends MatPaginatorIntl {
getRangeLabel = function (page, pageSize, length) {
if (length === 0 || pageSize === 0) {
return '0/' + length;
}
length = Math.max(length, 0);
const startIndex = page * pageSize;
// If the start index exceeds the list length, do not try and fix the end index to the end.
const endIndex = startIndex < length ?
Math.min(startIndex + pageSize, length) :
startIndex + pageSize;
return endIndex + ' / ' + length;
};
}
2.Add a customIntl to you module where you import the MatPaginator.
imports: [
...
MatPaginatorModule,
],
providers: [
...
{provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl}
]

Related

Is there a way to average only some rows of data in a sheet

I have several sheets that import various scores based on file reviews for different areas. I want to calculate an office average for those offices who have had more than one review in each period, but there's no way to tell ahead of time which offices are going to have more than one, so in each list there could be
office 1 score
office 2 score
office 2 score
office 3 score
Etc.
Is there a way to automate this, eg find duplicates and average, or do I have to look through after the imports and do it by hand?
Cheers :)
Meg
You can use the query function in Sheets.
Put this in cell E1:
=query(A:C,"select B,avg(C) where B is not null group by B label avg(C) 'Office average' ",1)
function getDataSubset() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const ssId = ss.getId();
const sheet = ss.getSheetByName('contact')
const sheetName = sheet.getName()
const lastRow = sheet.getLastRow();
const lastCol = sheet.getLastColumn();
// let theQuery = "SELECT * WHERE job ='a job'" // works
let theQuery = "SELECT A, B WHERE E ='a job' AND G > 30" //works
// with header row - result is an array of objects if header row is specified
// const a1Range = sheet.getDataRange().getA1Notation();
// let result = Utils.gvizQuery(
// ssId // YOUR_SPREADSHEET_ID
// ,theQuery
// ,sheetName // can be a number (the sheetId), or the name of the sheet; if not needed, but headers are, pass in undefined
// ,a1Range // specify range, ex: `A2:O`
// ,1 // HEADER_ROW_INDEX_IF_NEEDED> - always a number
// );
// no header row - result is an array of arrays
const a1Range = sheet.getRange(2,1,lastRow,lastCol).getA1Notation();
let result = Utils.gvizQuery(
ssId // YOUR_SPREADSHEET_ID
,theQuery
,sheetName // can be a number (the sheetId), or the name of the sheet; if not needed, but headers are, pass in undefined
,a1Range // specify range, ex: `A2:O`
// HEADER_ROW_INDEX_IF_NEEDED> - always a number
);
console.log( JSON.stringify(result) );
}
/**
* https://stackoverflow.com/questions/51327982/how-to-use-google-sheets-query-or-google-visualization-api-from-apps-script/51328419#51328419
*/
(function(context) {
const Utils = (context.Utils || (context.Utils = {}));
/**
* Queries a spreadsheet using Google Visualization API's Datasoure Url.
*
* #param {String} ssId Spreadsheet ID.
* #param {String} query Query string.
* #param {String|Number} sheetId Sheet Id (gid if number, name if string). [OPTIONAL]
* #param {String} range Range [OPTIONAL]
* #param {Number} headers Header rows. [OPTIONAL]
*/
Utils.gvizQuery = function(ssId, query, sheetId, range, headers) {
var response = JSON.parse( UrlFetchApp
.fetch(
Utilities.formatString(
"https://docs.google.com/spreadsheets/d/%s/gviz/tq?tq=%s%s%s%s",
ssId,
encodeURIComponent(query),
(typeof sheetId === "number") ? "&gid=" + sheetId :
(typeof sheetId === "string") ? "&sheet=" + sheetId :
"",
(typeof range === "string") ? "&range=" + range :
"",
"&headers=" + ((typeof headers === "number" && headers > 0) ? headers : "0")
),
{
"headers":{
"Authorization":"Bearer " + ScriptApp.getOAuthToken()
}
}
)
.getContentText()
.replace("/*O_o*/\n", "") // remove JSONP wrapper
.replace(/(google\.visualization\.Query\.setResponse\()|(\);)/gm, "") // remove JSONP wrapper
),
table = response.table,
rows;
if (typeof headers === "number") {
rows = table.rows.map(function(row) {
return table.cols.reduce(
function(acc, col, colIndex) {
acc[col.label] = row.c[colIndex] && row.c[colIndex].v;
return acc;
},
{}
);
});
} else {
rows = table.rows.map(function(row) {
return row.c.reduce(
function(acc, col) {
acc.push(col && col.v);
return acc;
},
[]
);
});
}
return rows;
};
Object.freeze(Utils);
})(this);

How to add more attributes in tooltip series in Angular NVD3 line chart

I need to add more attributes in tooltip series in Angular NVD3 line chart, if possible, without modifying the NVD3 source code. I know there are similar posts, but none of them covers this scenario.
Here is my tooltip section in options:
interactiveLayer: {
tooltip: {
contentGenerator: function (d) {
// output is key, value, color, which is the default for tooltips
console.log(JSON.stringify(d.series[0]));
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1)"}
// and I need more attributes to be added
// into data points, such as label, count, location (see data below)
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1), "label" : "some label", "count" : 23, "location" : "Paris"}
}
}
}
And here is my data:
$scope.data =
[
{
values: FirstGraphPointsArray,
key: 'Name',
color: 'rgba(255,140,0, 1)'
},
{
values: SecondGraphPointsArray
key: 'City',
color: 'rgba(255,140,0, 1)'
}
]
Finally, the structure of the arrays in data:
FirstGraphPointsArray -> [{ x: xVariable, y: yVariable, label: labelVariable, count: countVariable, location : locationVariable }, {second element...}, {third element...}];
SecondGraphPointsArray -> [a similar array...]
How to get more attributes (label, count, location) from these arrays into the contentGenerator: function (d). As mentioned above, I only receive the default ones from within function parameter (d)
console.log(JSON.stringify(d.series[0]));
//{"key":"Name","value":1000,"color":"rgba(255,140,0, 1)"}
I came up with a solution and wanted to share it, in case someone else comes across the same task. I ended up accessing some of the parameters from d through the default route - function(d), while some of the custom ones - directly from $scope.data.
Important: using the d.index, which indicates the place of the data point in the list is critical hear. This makes sure that for any given index the parameters pulled from the function(d) and those of pulled directly, belong to the same data point (see the code below).
interactiveLayer: {
tooltip: {
contentGenerator: function (d) {
var customTooltipcontent = "<h6 style='font-weight:bold'>" + d.value + "</h6>";
customTooltipcontent += "<table class='custom-tooltip-table'>";
customTooltipcontent += "<tr style='border-bottom: 1px solid green;'><td></td><td>Name</td><td>Value</td><td>Count</td></tr>";
for (var i = 0; i < d.series.length; i++) {
customTooltipcontent += "<tr><td><div style='width:10px; height:10px; background:" + d.series[i].color + "'></div></td><td>" + d.series[i].key + "</td><td>" + d.series[i].value + "</td><td>" + $scope.data[0].values[d.index].count + "</td><td>" + $scope.data[0].values[d.index].location + "</td></tr>"
}
customTooltipcontent += "</table>";
return (customTooltipcontent);
}
}
}

Extract URL from copied text in Google Sheets [duplicate]

I have a sheet where hyperlink is set in cell, but not through formula. When clicked on the cell, in "fx" bar it only shows the value.
I searched on web but everywhere, the info is to extract hyperlink by using getFormula().
But in my case there is no formula set at all.
I can see hyperlink as you can see in image, but it's not there in "formula/fx" bar.
How to get hyperlink of that cell using Apps Script or any formula?
When a cell has only one URL, you can retrieve the URL from the cell using the following simple script.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var url = sheet.getRange("A2").getRichTextValue().getLinkUrl(); //removed empty parentheses after getRange in line 2
Source: https://gist.github.com/tanaikech/d39b4b5ccc5a1d50f5b8b75febd807a6
When Excel file including the cells with the hyperlinks is converted to Google Spreadsheet, such situation can be also seen. In my case, I retrieve the URLs using Sheets API. A sample script is as follows. I think that there might be several solutions. So please think of this as one of them.
When you use this script, please enable Sheets API at Advanced Google Services and API console. You can see about how to enable Sheets API at here.
Sample script:
var spreadsheetId = "### spreadsheetId ###";
var res = Sheets.Spreadsheets.get(spreadsheetId, {ranges: "Sheet1!A1:A10", fields: "sheets/data/rowData/values/hyperlink"});
var sheets = res.sheets;
for (var i = 0; i < sheets.length; i++) {
var data = sheets[i].data;
for (var j = 0; j < data.length; j++) {
var rowData = data[j].rowData;
for (var k = 0; k < rowData.length; k++) {
var values = rowData[k].values;
for (var l = 0; l < values.length; l++) {
Logger.log(values[l].hyperlink) // You can see the URL here.
}
}
}
}
Note:
Please set spreadsheetId.
Sheet1!A1:A10 is a sample. Please set the range for your situation.
In this case, each element of rowData is corresponding to the index of row. Each element of values is corresponding to the index of column.
References:
Method: spreadsheets.get
If this was not what you want, please tell me. I would like to modify it.
Hey all,
I hope this helps you save some dev time, as it was a rather slippery one to pin down...
This custom function will take all hyperlinks in a Google Sheets cell, and return them as text formatted based on the second parameter as either [JSON|HTML|NAMES_ONLY|URLS_ONLY].
Parameters:
cellRef : You must provide an A1 style cell reference to a cell.
Hint: To do this within a cell without hard-coding
a string reference, you can use the CELL function.
eg: "=linksToTEXT(CELL("address",C3))"
style : Defines the formatting of the output string.
Valid arguments are : [JSON|HTML|NAMES_ONLY|URLS_ONLY].
Sample Script
/**
* Custom Google Sheet Function to convert rich-text
* links into Readable links.
* Author: Isaac Dart ; 2022-01-25
*
* Params
* cellRef : You must provide an A1 style cell reference to a cell.
* Hint: To do this within a cell without hard-coding
* a string reference, you can use the CELL function.
* eg: "=linksToTEXT(CELL("address",C3))"
*
* style : Defines the formatting of the output string.
* Valid arguments are : [JSON|HTML|NAMES_ONLY|URLS_ONLY].
*
*/
function convertCellLinks(cellRef = "H2", style = "JSON") {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange(cellRef).getCell(1,1);
var runs = cell.getRichTextValue().getRuns();
var ret = "";
var lf = String.fromCharCode(10);
runs.map(r => {
var _url = r.getLinkUrl();
var _text = r.getText();
if (_url !== null && _text !== null) {
_url = _url.trim(); _text = _text.trim();
if (_url.length > 0 && _text.length > 0) {
switch(style.toUpperCase()) {
case "HTML": ret += '' + _text + '}' + lf; break;
case "TEXT": ret += _text + ' : "' + _url + '"' + lf; break;
case "NAMES_ONLY" : ret += _text + lf; break;
case "URLS_ONLY" : ret += _url + lf; break;
//JSON default : ...
default: ret += (ret.length>0?(','+ lf): '') +'{name : "' + _text + '", url : "' + _url + '"}' ; break;
}
ret += lf;
}
}
});
if (style.toUpperCase() == "JSON") ret = '[' + ret + ']';
//Logger.log(ret);
return ret;
}
Cheers,
Isaac
I tried solution 2:
var urls = sheet.getRange('A1:A10').getRichTextValues().map( r => r[0].getLinkUrl() ) ;
I got some links, but most of them yielded null.
I made a shorter version of solution 1, which yielded all the links.
const id = SpreadsheetApp.getActive().getId() ;
let res = Sheets.Spreadsheets.get(id,
{ranges: "Sheet1!A1:A10", fields: "sheets/data/rowData/values/hyperlink"});
var urls = res.sheets[0].data[0].rowData.map(r => r.values[0].hyperlink) ;

Google AdWords script issue

I am trying to set up an AdWords script for the first time but cannot get it to function properly. It is essentially supposed to crawl all of our clients' AdWords accounts, send all of the account information to a Google Sheet, and send me an email to let me know if there are any anomalies detected in any of the accounts. I have not had any luck with getting the info to send to the Google sheet, let a lone an email notification. This is the primary error I'm currently getting when I preview the script: TypeError: Cannot call method "getValue" of null. (line 510)
Here is the Google resource page (https://developers.google.com/adwords/scripts/docs/solutions/mccapp-account-anomaly-detector) for the script and the actual script itself that I'm using is below.
Any recommendations on how to get this to function properly would be greatly appreciated. Thank you!
// Copyright 2017, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* #name MCC Account Anomaly Detector
*
* #fileoverview The MCC Account Anomaly Detector alerts the advertiser whenever
* one or more accounts in a group of advertiser accounts under an MCC account
* is suddenly behaving too differently from what's historically observed. See
* https://developers.google.com/adwords/scripts/docs/solutions/mccapp-account-anomaly-detector
* for more details.
*
* #author AdWords Scripts Team [adwords-scripts#googlegroups.com]
*
* #version 1.4
*
* #changelog
* - version 1.4
* - Added conversions to tracked statistics.
* - version 1.3.2
* - Added validation for external spreadsheet setup.
* - version 1.3.1
* - Improvements to time zone handling.
* - version 1.3
* - Cleanup the script a bit for easier debugging and maintenance.
* - version 1.2
* - Added AdWords API report version.
* - version 1.1
* - Fix the script to work in accounts where there is no stats.
* - version 1.0
* - Released initial version.
*/
var SPREADSHEET_URL = 'https://docs.google.com/a/altitudemarketing.com/spreadsheets/d/1ELWZPcGLqf7n9GDnTx5o7xWOFZHVbgaLakeXAu5NY-E/edit?usp=sharing';
var CONFIG = {
// Uncomment below to include an account label filter
// ACCOUNT_LABEL: 'High Spend Accounts'
};
var CONST = {
FIRST_DATA_ROW: 12,
FIRST_DATA_COLUMN: 2,
MCC_CHILD_ACCOUNT_LIMIT: 50,
TOTAL_DATA_COLUMNS: 9
};
var STATS = {
'NumOfColumns': 4,
'Impressions':
{'Column': 3, 'Color': 'red', 'AlertRange': 'impressions_alert'},
'Clicks': {'Column': 4, 'Color': 'orange', 'AlertRange': 'clicks_alert'},
'Conversions':
{'Column': 5, 'Color': 'dark yellow 2', 'AlertRange': 'conversions_alert'},
'Cost': {'Column': 6, 'Color': 'yellow', 'AlertRange': 'cost_alert'}
};
var DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday'];
/**
* Configuration to be used for running reports.
*/
var REPORTING_OPTIONS = {
// Comment out the following line to default to the latest reporting version.
apiVersion: 'v201605'
};
function main() {
var account;
var alertText = [];
Logger.log('Using spreadsheet - %s.', SPREADSHEET_URL);
var spreadsheet = validateAndGetSpreadsheet(SPREADSHEET_URL);
spreadsheet.setSpreadsheetTimeZone(AdWordsApp.currentAccount().getTimeZone());
var dataRow = CONST.FIRST_DATA_ROW;
SheetUtil.setupData(spreadsheet);
Logger.log('MCC account: ' + mccManager.mccAccount().getCustomerId());
while (account = mccManager.next()) {
Logger.log('Processing account ' + account.getCustomerId());
alertText.push(processAccount(account, spreadsheet, dataRow));
dataRow++;
}
sendEmail(mccManager.mccAccount(), alertText, spreadsheet);
}
/**
* For each of Impressions, Clicks, Conversions, and Cost, check to see if the
* values are out of range. If they are, and no alert has been set in the
* spreadsheet, then 1) Add text to the email, and 2) Add coloring to the cells
* corresponding to the statistic.
*
* #return {string} the next piece of the alert text to include in the email.
*/
function processAccount(account, spreadsheet, startingRow) {
var sheet = spreadsheet.getSheets()[0];
var thresholds = SheetUtil.thresholds();
var today = AdWordsApp.report(SheetUtil.getTodayQuery(), REPORTING_OPTIONS);
var past = AdWordsApp.report(SheetUtil.getPastQuery(), REPORTING_OPTIONS);
var hours = SheetUtil.hourOfDay();
var todayStats = accumulateRows(today.rows(), hours, 1); // just one week
var pastStats = accumulateRows(past.rows(), hours, SheetUtil.weeksToAvg());
var alertText = ['Account ' + account.getCustomerId()];
var validWhite = ['', 'white', '#ffffff']; // these all count as white
// Colors cells that need alerting, and adds text to the alert email body.
function generateAlert(field, emailAlertText) {
// There are 2 cells to check, for Today's value and Past value
var bgRange = [
sheet.getRange(startingRow, STATS[field].Column, 1, 1),
sheet.getRange(startingRow, STATS[field].Column + STATS.NumOfColumns,
1, 1)
];
var bg = [bgRange[0].getBackground(), bgRange[1].getBackground()];
// If both backgrounds are white, change background Colors
// and update most recent alert time.
if ((-1 != validWhite.indexOf(bg[0])) &&
(-1 != validWhite.indexOf(bg[1]))) {
bgRange[0].setBackground([[STATS[field]['Color']]]);
bgRange[1].setBackground([[STATS[field]['Color']]]);
spreadsheet.getRangeByName(STATS[field]['AlertRange']).
setValue('Alert at ' + hours + ':00');
alertText.push(emailAlertText);
}
}
if (thresholds.Impressions &&
todayStats.Impressions < pastStats.Impressions * thresholds.Impressions) {
generateAlert('Impressions',
' Impressions are too low: ' + todayStats.Impressions +
' Impressions by ' + hours + ':00, expecting at least ' +
parseInt(pastStats.Impressions * thresholds.Impressions));
}
if (thresholds.Clicks &&
todayStats.Clicks < (pastStats.Clicks * thresholds.Clicks).toFixed(1)) {
generateAlert('Clicks',
' Clicks are too low: ' + todayStats.Clicks +
' Clicks by ' + hours + ':00, expecting at least ' +
(pastStats.Clicks * thresholds.Clicks).toFixed(1));
}
if (thresholds.Conversions &&
todayStats.Conversions <
(pastStats.Conversions * thresholds.Conversions).toFixed(1)) {
generateAlert(
'Conversions',
' Conversions are too low: ' + todayStats.Conversions +
' Conversions by ' + hours + ':00, expecting at least ' +
(pastStats.Conversions * thresholds.Conversions).toFixed(1));
}
if (thresholds.Cost &&
todayStats.Cost > (pastStats.Cost * thresholds.Cost).toFixed(2)) {
generateAlert(
'Cost',
' Cost is too high: ' + todayStats.Cost + ' ' +
account.getCurrencyCode() + ' by ' + hours +
':00, expecting at most ' +
(pastStats.Cost * thresholds.Cost).toFixed(2));
}
// If no alerts were triggered, we will have only the heading text. Remove it.
if (alertText.length == 1) {
alertText = [];
}
var dataRows = [[
account.getCustomerId(), todayStats.Impressions, todayStats.Clicks,
todayStats.Conversions, todayStats.Cost, pastStats.Impressions.toFixed(0),
pastStats.Clicks.toFixed(1), pastStats.Conversions.toFixed(1),
pastStats.Cost.toFixed(2)
]];
sheet.getRange(startingRow, CONST.FIRST_DATA_COLUMN,
1, CONST.TOTAL_DATA_COLUMNS).setValues(dataRows);
return alertText;
}
var SheetUtil = (function() {
var thresholds = {};
var upToHour = 1; // default
var weeks = 26; // default
var todayQuery = '';
var pastQuery = '';
var setupData = function(spreadsheet) {
Logger.log('Running setupData');
spreadsheet.getRangeByName('date').setValue(new Date());
spreadsheet.getRangeByName('account_id').setValue(
mccManager.mccAccount().getCustomerId());
var getThresholdFor = function(field) {
thresholds[field] = parseField(spreadsheet.
getRangeByName(field).getValue());
};
getThresholdFor('Impressions');
getThresholdFor('Clicks');
getThresholdFor('Conversions');
getThresholdFor('Cost');
var now = new Date();
// Basic reporting statistics are usually available with no more than a 3-hour
// delay.
var upTo = new Date(now.getTime() - 3 * 3600 * 1000);
upToHour = parseInt(getDateStringInTimeZone('h', upTo));
spreadsheet.getRangeByName('timestamp').setValue(
DAYS[getDateStringInTimeZone('u', now)] + ', ' + upToHour + ':00');
if (upToHour == 1) {
// First run of the day, clear existing alerts.
spreadsheet.getRangeByName(STATS['Clicks']['AlertRange']).clearContent();
spreadsheet.getRangeByName(STATS['Impressions']['AlertRange']).
clearContent();
spreadsheet.getRangeByName(STATS['Conversions']['AlertRange'])
.clearContent();
spreadsheet.getRangeByName(STATS['Cost']['AlertRange']).clearContent();
// Reset background and font Colors for all data rows.
var bg = [];
var ft = [];
var bg_single = [
'white', 'white', 'white', 'white', 'white', 'white', 'white', 'white',
'white'
];
var ft_single = [
'black', 'black', 'black', 'black', 'black', 'black', 'black', 'black',
'black'
];
// Construct a 50-row array of colors to set.
for (var a = 0; a < CONST.MCC_CHILD_ACCOUNT_LIMIT; ++a) {
bg.push(bg_single);
ft.push(ft_single);
}
var dataRegion = spreadsheet.getSheets()[0].getRange(
CONST.FIRST_DATA_ROW, CONST.FIRST_DATA_COLUMN,
CONST.MCC_CHILD_ACCOUNT_LIMIT, CONST.TOTAL_DATA_COLUMNS);
dataRegion.setBackgrounds(bg);
dataRegion.setFontColors(ft);
}
var weeksStr = spreadsheet.getRangeByName('weeks').getValue();
weeks = parseInt(weeksStr.substring(0, weeksStr.indexOf(' ')));
var dateRangeToCheck = getDateStringInPast(0, upTo);
var dateRangeToEnd = getDateStringInPast(1, upTo);
var dateRangeToStart = getDateStringInPast(1 + weeks * 7, upTo);
var fields = 'HourOfDay, DayOfWeek, Clicks, Impressions, Conversions, Cost';
todayQuery = 'SELECT ' + fields +
' FROM ACCOUNT_PERFORMANCE_REPORT DURING ' + dateRangeToCheck + ',' +
dateRangeToCheck;
pastQuery = 'SELECT ' + fields +
' FROM ACCOUNT_PERFORMANCE_REPORT WHERE DayOfWeek=' +
DAYS[getDateStringInTimeZone('u', now)].toUpperCase() +
' DURING ' + dateRangeToStart + ',' + dateRangeToEnd;
};
var getThresholds = function() { return thresholds; };
var getHourOfDay = function() { return upToHour; };
var getWeeksToAvg = function() { return weeks; };
var getPastQuery = function() { return pastQuery; };
var getTodayQuery = function() { return todayQuery; };
// The SheetUtil public interface.
return {
setupData: setupData,
thresholds: getThresholds,
hourOfDay: getHourOfDay,
weeksToAvg: getWeeksToAvg,
getPastQuery: getPastQuery,
getTodayQuery: getTodayQuery
};
})();
function sendEmail(account, alertTextArray, spreadsheet) {
var bodyText = '';
alertTextArray.forEach(function(alertText) {
// When zero alerts, this is an empty array, which we don't want to add.
if (alertText.length == 0) { return }
bodyText += alertText.join('\n') + '\n\n';
});
bodyText = bodyText.trim();
var email = spreadsheet.getRangeByName('email').getValue();
if (bodyText.length > 0 && email && email.length > 0 &&
email != 'foo#example.com') {
Logger.log('Sending Email');
MailApp.sendEmail(email,
'AdWords Account ' + account.getCustomerId() + ' misbehaved.',
'Your account ' + account.getCustomerId() +
' is not performing as expected today: \n\n' +
bodyText + '\n\n' +
'Log into AdWords and take a look: ' +
'adwords.google.com\n\nAlerts dashboard: ' +
SPREADSHEET_URL);
}
else if (bodyText.length == 0) {
Logger.log('No alerts triggered. No email being sent.');
}
}
function toFloat(value) {
value = value.toString().replace(/,/g, '');
return parseFloat(value);
}
function parseField(value) {
if (value == 'No alert') {
return null;
} else {
return toFloat(value);
}
}
function accumulateRows(rows, hours, weeks) {
var result = {Clicks: 0, Impressions: 0, Conversions: 0, Cost: 0};
while (rows.hasNext()) {
var row = rows.next();
var hour = row['HourOfDay'];
if (hour < hours) {
result = addRow(row, result, 1 / weeks);
}
}
return result;
}
function addRow(row, previous, coefficient) {
if (!coefficient) {
coefficient = 1;
}
if (!row) {
row = {Clicks: 0, Impressions: 0, Conversions: 0, Cost: 0};
}
if (!previous) {
previous = {Clicks: 0, Impressions: 0, Conversions: 0, Cost: 0};
}
return {
Clicks: parseInt(row['Clicks']) * coefficient + previous.Clicks,
Impressions:
parseInt(row['Impressions']) * coefficient + previous.Impressions,
Conversions:
parseInt(row['Conversions']) * coefficient + previous.Conversions,
Cost: toFloat(row['Cost']) * coefficient + previous.Cost
};
}
function checkInRange(today, yesterday, coefficient, field) {
var yesterdayValue = yesterday[field] * coefficient;
if (today[field] > yesterdayValue * 2) {
Logger.log('' + field + ' too much');
} else if (today[field] < yesterdayValue / 2) {
Logger.log('' + field + ' too little');
}
}
/**
* Produces a formatted string representing a date in the past of a given date.
*
* #param {number} numDays The number of days in the past.
* #param {date} date A date object. Defaults to the current date.
* #return {string} A formatted string in the past of the given date.
*/
function getDateStringInPast(numDays, date) {
date = date || new Date();
var MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
var past = new Date(date.getTime() - numDays * MILLIS_PER_DAY);
return getDateStringInTimeZone('yyyyMMdd', past);
}
/**
* Produces a formatted string representing a given date in a given time zone.
*
* #param {string} format A format specifier for the string to be produced.
* #param {date} date A date object. Defaults to the current date.
* #param {string} timeZone A time zone. Defaults to the account's time zone.
* #return {string} A formatted string of the given date in the given time zone.
*/
function getDateStringInTimeZone(format, date, timeZone) {
date = date || new Date();
timeZone = timeZone || AdWordsApp.currentAccount().getTimeZone();
return Utilities.formatDate(date, timeZone, format);
}
/**
* Module that deals with fetching and iterating through multiple accounts.
*
* #return {object} callable functions corresponding to the available
* actions. Specifically, it currently supports next, current, mccAccount.
*/
var mccManager = (function() {
var accountIterator;
var mccAccount;
var currentAccount;
// Private one-time init function.
var init = function() {
var accountSelector = MccApp.accounts();
// Use this to limit the accounts that are being selected in the report.
if (CONFIG.ACCOUNT_LABEL) {
accountSelector.withCondition("LabelNames CONTAINS '" +
CONFIG.ACCOUNT_LABEL + "'");
}
accountSelector.withLimit(CONST.MCC_CHILD_ACCOUNT_LIMIT);
accountIterator = accountSelector.get();
mccAccount = AdWordsApp.currentAccount(); // save the mccAccount
currentAccount = AdWordsApp.currentAccount();
};
/**
* After calling this, AdWordsApp will have the next account selected.
* If there are no more accounts to process, re-selects the original
* MCC account.
*
* #return {AdWordsApp.Account} The account that has been selected.
*/
var getNextAccount = function() {
if (accountIterator.hasNext()) {
currentAccount = accountIterator.next();
MccApp.select(currentAccount);
return currentAccount;
}
else {
MccApp.select(mccAccount);
return null;
}
};
/**
* Returns the currently selected account. This is cached for performance.
*
* #return {AdWords.Account} The currently selected account.
*/
var getCurrentAccount = function() {
return currentAccount;
};
/**
* Returns the original MCC account.
*
* #return {AdWords.Account} The original account that was selected.
*/
var getMccAccount = function() {
return mccAccount;
};
// Set up internal variables; called only once, here.
init();
// Expose the external interface.
return {
next: getNextAccount,
current: getCurrentAccount,
mccAccount: getMccAccount
};
})();
/**
* Validates the provided spreadsheet URL and email address
* to make sure that they're set up properly. Throws a descriptive error message
* if validation fails.
*
* #param {string} spreadsheeturl The URL of the spreadsheet to open.
* #return {Spreadsheet} The spreadsheet object itself, fetched from the URL.
* #throws {Error} If the spreadsheet URL or email hasn't been set
*/
function validateAndGetSpreadsheet(spreadsheeturl) {
if (spreadsheeturl == 'YOUR_SPREADSHEET_URL') {
throw new Error('Please specify a valid Spreadsheet URL. You can find' +
' a link to a template in the associated guide for this script.');
}
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheeturl);
var email = spreadsheet.getRangeByName('email').getValue();
if ('foo#example.com' == email) {
throw new Error('Please either set a custom email address in the' +
' spreadsheet, or set the email field in the spreadsheet to blank' +
' to send no email.');
}
return spreadsheet;
}

Google spreadsheet: Download all the sheets at once

When working with google spreadsheet, how to download all the sheets at once?
I want to use the option:
Comma-separated values
But it only download the current sheet, how to get them all?
For anyone who navigates to this question, trying to download all the tabs in their Google spreadsheets as CSV files at once, even in 2021, there does not seem to be a GUI button to do this. At least I could not see anything. The answer by #Amit Agarwal does well, to get all sheets, but if your file has comma-delimited data in cells, then data could get mangled.
I took Amit's approach https://stackoverflow.com/a/28711961 and combined it with Michael Derazon and Aaron Davis's approach here https://gist.github.com/mrkrndvs/a2c8ff518b16e9188338cb809e06ccf1 to dump all the tabs of a chosen Google spreadsheet into a folder in Google Drive. You can then just download the folder with a single click.
The following is Google script, not exactly a Javascript, and you would have to copy-paste this in https://script.google.com/ login with your Google id, and then create a project and then create a script app, and save and execute this.
// https://stackoverflow.com/a/28711961
function export_sheets_as_csv_to_folder() {
// Sheet id is in URL https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit#gid=IGNORE
var ss = SpreadsheetApp.openById('YOUR_SHEET_ID');
var sheets = ss.getSheets();
if (sheets === undefined || sheets.length === 0) {
return;
}
var passThroughFolder = DriveApp.createFolder('YOUR_PREFERRED_FOLDER_NAME_IN_DRIVE');
for (var s in sheets) {
var csv = convertRangeToCsvFile_(sheets[s])
passThroughFolder.createFile(sheets[s].getName() + ".csv", csv);
}
}
// https://gist.github.com/mrkrndvs/a2c8ff518b16e9188338cb809e06ccf1
function convertRangeToCsvFile_(sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
After clicking download > pdf, select export > worksheet (instead of current sheet which is the default)
You can use Google Scripts to save all the sheets of a spreadsheet into separate files.
function myFunction() {
var ss = SpreadsheetApp.openById(SHEET_ID);
var sheets = ss.getSheets();
for (var s in sheets) {
var csv = "";
var data = sheets[s].getDataRange().getValues();
for (d in data) {
csv += data[d].join(",") + "\n";
}
DriveApp.createFile(sheets[s].getName() + ".csv", csv);
}
}
the answer from #Soham works amazingly but it doesn't handle multiline values. It would be an easy fix just to add more checks to character \n along with , but I took the liberty to rewrite the function using map (and string.includes) so it is more concise.
function convertRangeToCsvFile_(sheet) {
return sheet.getDataRange().getValues()
.map(row => row.map(value => value.toString())
.map(value => (value.includes("\n") || value.includes(",")) ? "\"" + value + "\"" : value)
.join(','))
.join('\n')
}
A slight variation on this that uses a zip instead of a folder to contain the sheets and does some modernizing of the great work done by keychera and Soham's answer.
You can use this as a bound script and it will add a menu item to the extensions menu:
// Code.gs
function exportSheetsToDrive() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheets = ss.getSheets();
if (sheets === undefined || sheets.length === 0) {
return;
}
const now = new Date();
const csvBlobs = sheets.map((sheet) => {
const name = sheet.getName();
const csv = convertSheetToCsv(sheet);
Logger.log({ name, length: csv.length });
return Utilities.newBlob(csv, MimeType.CSV, `${name}.csv`)
});
const zipName = `export_${ss.getName()}_${now.toISOString()}.zip`;
const zip = Utilities.zip(csvBlobs, zipName);
DriveApp.createFile(zip);
}
function convertSheetToCsv(sheet) {
return sheet
.getDataRange()
.getValues()
.map((row) =>
row
.map((value) => value.toString())
.map((value) =>
value.includes("\n") || value.includes(",")
? '"' + value + '"'
: value
)
.join(",")
)
.join("\n");
}
and
// Menu.gs
function onOpen(e) {
const menu = SpreadsheetApp.getUi().createAddonMenu();
menu
.addItem('Export all sheets as CSV to Drive', 'exportSheetsToDrive')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}

Resources