I'm currently using a script that hides rows if column M equals "Yes", but I want it to hide rows if column M equals "Yes" or "No". I tried
if(r[0] == "Yes","No")
but that hid all rows. Help?
function onOpen() {
var s = SpreadsheetApp.getActive().getSheetByName('Form Responses 1');
s.showRows(1, s.getMaxRows());
s.getRange('M:M')
.getValues()
.forEach( function (r, i) {
if (r[0] == 'YES')
s.hideRows(i + 1);
});
}
I tried
function onOpen() {
var s = SpreadsheetApp.getActive().getSheetByName('Form Responses 1');
s.showRows(1, s.getMaxRows());
s.getRange('M:M')
.getValues()
.forEach( function (r, i) {
if (r[0] == 'YES') || if (r[0] =='No')
s.hideRows(i + 1);
});
}
But that only hid rows with "yes"
Related
I am trying to concatenate or combine a few cells together and keep their individual styles.
For instance:
A1: Mr (Arial, Red, size 10)
A2: Joseph (Courier, Blue, size 20)
A3: Lion (Arial, Green, size 15)
Using the function =A1&" "&A2&" "&A3
A5: Mr Joseph Lion (Default font, default colour, default Size)
In the Concatenated cell A5, all the fonts, sizes and colours go back to default.
Is there a way to combine the values and maintain the styles.
Thank you all in advance.
You can use this function (RICHTEXTCONCAT()) to concatenate rich text from your Sheets:
function isCell(obj) {
return (typeof obj == "object" && obj.toString() == "Range" && obj.getHeight() == 1 && obj.getWidth() == 1);
}
function RICHTEXTCONCAT() {
var nargs = arguments.length;
var resultText = "";
var styles = [];
for (var i=0; i<nargs; i++) {
var arg = arguments[i];
if (isCell(arg)) {
var startPos = resultText.length;
resultText += arg.getValue();
var rtv = arg.getRichTextValue();
if (rtv) {
var runs = rtv.getRuns();
for (var j=0; j<runs.length; j++) {
styles.push({startIndex: startPos + runs[j].getStartIndex(),
endIndex: startPos + runs[j].getEndIndex(),
textStyle: runs[j].getTextStyle().copy().build()});
}
}
} else if (typeof arg == "string") {
resultText += arg;
} else {
throw new Error("Unsupported type " + typeof arg + " for argument " + (i+1) + ". Must be a cell or a string.");
}
}
var result = SpreadsheetApp.newRichTextValue().setText(resultText);
for (var i=0; i<styles.length; i++) {
if (styles[i].startIndex === styles[i].endIndex) continue;
result.setTextStyle(styles[i].startIndex,
styles[i].endIndex,
styles[i].textStyle);
}
return result.build();
}
In theory, you could use the function as a custom function, so that it could be used in a cell such as:
=RICHTEXTCONCAT(A1, " ", A2, " ", A3)
However, Sheets does not interpret rich text return values from custom functions. That means that the only option you have is to manually call a Google Apps Script function that uses setRichTextValue() in order to execute it. An example:
function myConcat() {
var sheet = SpreadsheetApp.getActive();
var range1 = sheet.getRange("A1");
var range2 = sheet.getRange("A2");
var range3 = sheet.getRange("A3");
var result = RICHTEXTCONCAT(range1, " ", range2, " ", range3);
var destinationRange = sheet.getRange("A5");
destinationRange.setRichTextValue(result);
}
If you are interested in Rich Text Value being a possible return value from a custom function, please consider filing a Feature Request into Google's Public Issue Tracker (https://issuetracker.google.com).
I want to change this
var cell = {
v: value,
s: {alignment: {horizontal:"left"}}
};
to add hyperlink formula on 'value' like this
`{ formula:'HYPERLINK("' + mainhyperlinkurl + '","Download.Zip")' };`
In the below addcell function code sample
function addCell(range, value, row, col, ws, isHeader) {
if (range.s.r > row) range.s.r = row;
if (range.s.c > col) range.s.c = col;
if (range.e.r < row) range.e.r = row;
if (range.e.c < col) range.e.c = col;
var cell = {
v: value,
s: {alignment: {horizontal:"left"}}
};
if (cell.v == null) cell.v = '-';
var cell_ref = XLSX.utils.encode_cell({
c: col,
r: row
});
//if (typeof cell.v === 'number') cell.t = 'n';
//if (!isNaN(cell.v)) cell.t = 'n';
//else
if (typeof cell.v === 'boolean') cell.t = 'b';
else if (cell.v instanceof Date) {
cell.t = 'n';
cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
} else cell.t = 's';
if(isHeader){
cell.s = {
font: {
bold:isHeader
}
};
}
ws[cell_ref] = cell;
}
waiting for your response, Thanks.
I am currently working on an Excel web Add-in where I am making an ajax call which sometimes returning a very large amount of data. After the data is returned I am iterating thought the data and loading values to cells in one sync. If the returned data is big enough it would crash the add-in. I have tried loading the data to the cells in batches, meaning for every 500 rows I tried to sync and then continue loading data into cells, but after loading the first 500 rows instead of continuing after the sync it exits out of the loop. I am new to Excel Js API and I am not sure I am doing this portion of my code correctly and I am unable to find any examples of this, any help would be appreciated.
function loadExcelData() {
Excel.run(function (context) {
var WebConnectAPI = "../../Data/GetExcelData";
$("#Info").html("")
var app = context.workbook.application;
app.load("calculationMode");
return context.sync()
.then(function () {
app.suspendApiCalculationUntilNextSync();
$.when(getExcelData(WebConnectAPI)).done(function (data) {
LoadDataV3(data, context);
}).fail(function (jqXHR, textStatus, errorThrown) {
$("#Error").html("Error:" + textStatus);
console.log("jqXHr:" + jqXHR + " Status:" + textStatus + " error:" + errorThrown);
});
});
}).catch (function (error) {
console.log("Error: " + error);
$("#Error").html(error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
function LoadDataV3(data, context) {
var workSheetName = "Sheet1";
var currentWorksheet = context.workbook.worksheets.getItem(workSheetName);
if (data.data.length != 0) {
for (var x = 0; x < data.data.length; x++) {
var y = 0
if (x % 500 == 0 && x != 0) {
context.sync();
loadCellData(currentWorksheet, data.data, x, y);
}
else {
loadCellData(currentWorksheet, data.data, x, y);
}
}
return context.sync()
.then(function () {
$('#Export-Data').show();
});
}
else {
$("#Info").html("No data was returned for your specific search criteria.")
}
}
function loadCellData(currentWorksheet,excelData,x,y) {
$.each(excelData[x], function (key, value) {
if (x == 0) {
var HeaderCell = currentWorksheet.getRange(tocellAddress(y + 1, x + 1));//Start on first row
var Cell = currentWorksheet.getRange(tocellAddress(y + 1, x + 2));//Start on second row
HeaderCell.values = [[key]];
Cell.values = [[value]];
HeaderCell.format.autofitColumns();
Cell.format.autofitColumns();
}
else {
var Cell = currentWorksheet.getRange(tocellAddress(y + 1, x + 2));//start on third row
Cell.values = [[value]];
Cell.format.autofitColumns();
}
y++;
});
}
The approach I took in my above code was not correct due to my misunderstanding of how the context.sync actually worked, as mentioned in the js api documentation you should really just need one context sync. For loading large amounts of data the data should be queued up in chunks of ranges and then sync once all data is queued.
I'm having some trouble getting the value of a column in a saved search via SuiteScript. Below is my code:
function KW_AutoCloseOldRA() {
var search = nlapiLoadSearch('transaction', 'customsearchopen_ras', null, null);
var columns = search.getColumns();
for (i = 0; i < columns.length; i++) {
nlapiLogExecution('DEBUG', 'Column #' + i + ' is ' + columns[i].getName());
}
var results = search.runSearch();
if (results) {
results.forEachResult(getResults);
}
}
function getResults(res) {
var message = res.getValue('tranid');
nlapiLogExecution('DEBUG', 'Result ' + message);
return true;
}
The search produces two columns, and the name of those columns output as expected in the DEBUG entry (internalid is column 0 and tranid is column 1). When looping through the results however, res.getValue('tranid') is always null. I can't seem to find what I'm doing wrong here.
Try getting the value using the columns object and its index like this:
function KW_AutoCloseOldRA() {
var search = nlapiLoadSearch('transaction', 'customsearchopen_ras', null, null);
var columns = search.getColumns();
for (i = 0; i < columns.length; i++) {
nlapiLogExecution('DEBUG', 'Column #' + i + ' is ' + columns[i].getName());
}
var results = search.runSearch();
if (results) {
results.forEachResult(getResults);
}
}
function getResults(res) {
var cols = res.getAllColumns();
var message = res.getValue(cols[1]);
nlapiLogExecution('DEBUG', 'Result ' + message);
return true;
}
I was looking for a solution to the problem of getting a blank default when using a lookup in a field in Sharepoint. Kit Menke's solution to "Dropdown field - first item should be blank" question works perfectly for my first field with a lookup. But I can't make it work if have more that one field in the same list where I need to insert a blank for each lookup field (works only for the first field). I tried adding a new "Web Part" and applying the same code to the second field, but doesn't work. Any ideas? Thanks in advance
Follow-up to my answer here: Dropdown field - first item should be blank
Version 2.0 allows you to add the names of your dropdowns to dropdownNames in the MyCustomExecuteFunction function. As with the first one, this will work only with required single select lookup fields. Also, in order to edit the page again and update your Content Editor Web Part you may have to choose a value for your dropdowns otherwise you get the dreaded An unexpected error has occurred.. Good luck! :D
<script type="text/javascript">
function GetDropdownByTitle(title) {
var dropdowns = document.getElementsByTagName('select');
for (var i = 0; i < dropdowns.length; i++) {
if (dropdowns[i].title === title) {
return dropdowns[i];
}
}
return null;
}
function GetOKButtons() {
var inputs = document.getElementsByTagName('input');
var len = inputs.length;
var okButtons = [];
for (var i = 0; i < len; i++) {
if (inputs[i].type && inputs[i].type.toLowerCase() === 'button' &&
inputs[i].id && inputs[i].id.indexOf('diidIOSaveItem') >= 0) {
okButtons.push(inputs[i]);
}
}
return okButtons;
}
function AddValueToDropdown(oDropdown, text, value, optionnumber){
var options = oDropdown.options;
var option = document.createElement('OPTION');
option.appendChild(document.createTextNode(text));
option.setAttribute('value',value);
if (typeof(optionnumber) == 'number' && options[optionnumber]) {
oDropdown.insertBefore(option,options[optionnumber]);
}
else {
oDropdown.appendChild(option);
}
oDropdown.options.selectedIndex = 0;
}
function WrapClickEvent(element, newFunction) {
var clickFunc = element.onclick;
element.onclick = function(event){
if (newFunction()) {
clickFunc();
}
};
}
function MyCustomExecuteFunction() {
// **** ADD YOUR REQUIRED SINGLE SELECT FIELDS HERE ***
var dropdownNames = [
'Large Lookup Field',
'My Dropdown Field'
];
var dropdownElements = [];
for (var d = 0; d < dropdownNames.length; d++) {
// find the dropdown
var dropdown = GetDropdownByTitle(dropdownNames[d]);
// comment this IF block out if you don't want an error displayed
// when the dropdown can't be found
if (null === dropdown) {
alert('Unable to get dropdown named ' + dropdownNames[d]);
continue;
}
AddValueToDropdown(dropdown, '', '', 0);
// collect all of our dropdowns
dropdownElements.push(dropdown);
}
// add a custom validate function to the page
var funcValidate = function() {
var isValid = true;
var message = "";
for (var d = 0; d < dropdownElements.length; d++) {
if (0 === dropdownElements[d].selectedIndex) {
// require a selection other than the first item (our blank value)
if (isValid) {
isValid = false;
} else {
message += "\n"; // already had one error so we need another line
}
message += "Please choose a value for " + dropdownNames[d] + ".";
}
}
if (!isValid) {
alert(message);
}
return isValid;
};
var okButtons = GetOKButtons();
for (var b = 0; b < okButtons.length; b++) {
WrapClickEvent(okButtons[b], funcValidate);
}
}
_spBodyOnLoadFunctionNames.push("MyCustomExecuteFunction");
</script>
How about prepending a null option to the select menu of sharepoint.Like,
$('#idOfSelectMenu').prepend('<option value="" selected>(None)</option>');
I used this approach and append this code only in the NewForm.aspx because in EditForm.aspx it will override the selected option.