How to set multiple filters in closedXML - closedxml

There are two unanswered questions out there on this:
Applying multiple filters in ClosedXML (SetAutoFilter) and
ClosedXML Excel filter rows by values in multiple columns
This code will leave a single filter on the last range:
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("AutoFilter");
ws.Cell("A1").Value = "Names";
ws.Cell("A2").Value = "John";
ws.Cell("A3").Value = "Hank";
ws.Cell("A4").Value = "Dagny";
var r1 = ws.Range("A1", "A4");
r1.SetAutoFilter();
ws.Cell("B1").Value = "Names";
ws.Cell("B2").Value = "John";
ws.Cell("B3").Value = "Hank";
ws.Cell("B4").Value = "Dagny";
var r2 = ws.Range("B1", "B4");
r2.SetAutoFilter();
wb.SaveAs(filterTest);
See the image: only one filter in excel file
How can I add multiple filters?

There is a misunderstanding of filters here!
One filter per page is the rule, code below produces the desired result.
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("AutoFilter");
ws.Cell("A1").Value = "Names";
ws.Cell("A2").Value = "John";
ws.Cell("A3").Value = "Hank";
ws.Cell("A4").Value = "Dagny";
ws.Cell("B1").Value = "id";
ws.Cell("B2").Value = "1";
ws.Cell("B3").Value = "2";
ws.Cell("B4").Value = "3";
var r2 = ws.Range("A1", "B4");
r2.SetAutoFilter();
wb.SaveAs(filtertest);
result

Related

Google forms list items with dynamic goto section

I found this answer posted here earlier.
function GoToPage() {
var form = FormApp.openById('MY FORM');
var spreadsheet = SpreadsheetApp.openById("MY SPREADSHEET");
var sheet = spreadsheet.getSheetByName("MY SHEET");
var list = form.getItemById("MY MULTIPLE CHOICE ID").asListItem()
var pagebreak01 = form.getItemById("PAGE BREAK ID 1").asPageBreakItem();
var pagebreak02 = form.getItemById("PAGE BREAK ID 2").asPageBreakItem();
var pagebreak03 = form.getItemById("PAGE BREAK ID 3").asPageBreakItem();
var choice1 = sheet.getRange("RANGE 1 FROM MY SHEET").getValues();
var choice2 = sheet.getRange("RANGE 2 FROM MY SHEET").getValues();
var choice3 = sheet.getRange("RANGE 3 FROM MY SHEET").getValues();
list.setChoices([
list.createChoice(choice1, pagebreak01),
list.createChoice(choice2, pagebreak02),
list.createChoice(choice3, pagebreak03)]);
}
when using a range larger than 1 in the choice# variables, this makes just one choice with all the items in the range separated by commas. how can I use this to make a list of choices that has a dynamic range?
My exact choices should be:
"** Add Location **" , goto newLocation section of form.
location 1, goto next section.
location 2, goto next section.
location 3, ect....
If you select new location and fill out the form to add a new location the script then adds that location name to the choices for the next time you fill out the form. so this list is continually growing larger.
function updateForm() {
var locationForm = form.getItemById("413015265").asListItem();
var equipmentForm = form.getItemById("2123556695").asListItem();
var newLocation = form.getItemById('231469190').asPageBreakItem();
var newItem = form.getItemById('90044295').asPageBreakItem();
var gotoIssue = form.getItemById('1493817332').asPageBreakItem();
var gotoLocation = form.getItemById('1425783734').asPageBreakItem();
var locations = tblLocations.getRange(2,2,tblLocations.getLastRow()-1,1).getValues();
var items = tblItems.getRange(2,2,tblItems.getLastRow()-1,1).getValues();
items = items.sort();
locations = locations.sort();
locationForm.setChoices([
locationForm.createChoice("** Add Location **",newLocation),
locationForm.createChoice(locations,gotoIssue)
]);
equipmentForm.setChoices([
equipmentForm.createChoice("** Add Item **",newItem),
equipmentForm.createChoice(items,gotoLocation)
]);
}
after running the above script I ended up with only 2 choices. 1 new location/item entry which works correctly, and 1 entry with all the current locations/items in the spreadsheet already, separated by commas. Can i just run a foreach loop inside the setChoices command?
function updateForm() {
var locationForm = form.getItemById("413015265").asListItem();
var equipmentForm = form.getItemById("2123556695").asListItem();
var newLocation = form.getItemById('231469190').asPageBreakItem();
var newItem = form.getItemById('90044295').asPageBreakItem();
var gotoIssue = form.getItemById('1493817332').asPageBreakItem();
var gotoLocation = form.getItemById('1425783734').asPageBreakItem();
var locations = tblLocations.getRange(2,2,tblLocations.getLastRow()-1,1).getValues();
var items = tblItems.getRange(2,2,tblItems.getLastRow()-1,1).getValues();
var locationChoices = [];
var itemChoices = [];
locationChoices[0] = locationForm.createChoice("** Add Location **",newLocation);
itemChoices[0] = equipmentForm.createChoice("** Add Item **",newItem);
items = items.sort();
locations = locations.sort();
for (var i=0;i<tblLocations.getLastRow()-1;i++){
locationChoices[i+1]= locationForm.createChoice(locations[i],gotoIssue);
}
locationForm.setChoices(locationChoices);
for (var i=0;i<tblItems.getLastRow()-1;i++){
itemChoices[i+1]= equipmentForm.createChoice(items[i],gotoLocation);
}
equipmentForm.setChoices(itemChoices);
}
I was able to figure it out. It's probably not the most beautiful solution but it works. :)

How can I use a variable as a parameter in getSheetByName?

I have the following code which generates some gslides slides from data in a spreadsheet. The code is attached to the gslides file and it works when the parameters for link/year are entered as strings. However, these parameters will sometimes vary from a set list (e.g. pull from a different sheet or from a different file) so the code sometimes needs to be edited.
I want to share this with colleagues who don't know how to use app scripts and so tried to edit it so that the link/year can be pulled from a textbox in one of the slides in the gslides file. They are pulling through ok but when I try to use it as a parameter I get an error for line 11 (var values = sheet.getRange('F2:aa2').getValues();) as the sheet returns as null.
I've tried wrapping it in quotes (" ' " + year + " ' ") but that doesn't work either.
Please let me know if I need to include more info or a link to the sheets/slides files.
function generateStarters() {
var deck = SlidesApp.getActivePresentation();
var slides = deck.getSlides();
var link = slides[2].getPageElements()[2].asShape().getText().asString()
var year = slides[2].getPageElements()[4].asShape().getText().asString()
var dataSpreadsheetUrl = link
var ss = SpreadsheetApp.openByUrl(dataSpreadsheetUrl);
var sheet = ss.getSheetByName(year);
var values = sheet.getRange('F2:aa2').getValues();
var templateSlide = slides[1];
var presLength = slides.length;
values.forEach(function(page){
if(page[0]){
var Q1 = page[0];
var A1 = page[1];
var Q2 = page[4];
var A2 = page[5];
var Q3 = page[8];
var A3 = page[9];
var Q4 = page[12];
var A4 = page[13];
var QK = page[16];
var AK = page[17];
var QF = page[20];
var AF = page[21];
templateSlide.duplicate(); //duplicate the template page
slides = deck.getSlides(); //update the slides array for indexes and length
newSlide = slides[3]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{q1}}',Q1);
shape.getText().replaceAllText('{{a1}}',A1);
shape.getText().replaceAllText('{{q2}}',Q2);
shape.getText().replaceAllText('{{a2}}',A2);
shape.getText().replaceAllText('{{q3}}',Q3);
shape.getText().replaceAllText('{{a3}}',A3);
shape.getText().replaceAllText('{{q4}}',Q4);
shape.getText().replaceAllText('{{a4}}',A4);
shape.getText().replaceAllText('{{qk}}',QK);
shape.getText().replaceAllText('{{ak}}',AK);
shape.getText().replaceAllText('{{qf}}',QF);
shape.getText().replaceAllText('{{af}}',AF);
});
presLength = slides.length;
newSlide.move(presLength);
}
});
} ```
The string from the slides file seems to always have a space at the end (from the textbox) so I just needed to add an extra line of code to remove that space.

Google web app server returns null even though logger.log confirms theirs data

I currently have a google web app that checks to see if the a value (predefined from dropdown list so it will always been in the column") is in a column, if it is, it returns information about that value. however i am trying to update it so if the value is not found in the column(user entered value), it searches a second column to see if anyone has entered that value before. the issue i am having is once it finds the user entered value, it collects the value of the cells adjacent to it and flicks it back to the client side HTML javascript, the client side is seeing it as null. It's currently working fine for the first section which uses the predefined drop down choices. it's still finding the correct information, its just the client side for some reason cannot see it. I am abit of a novice when it comes to coding so any help anyone could provide would be GREATLY appreciated.
function sendFleet(e){ // This code sends the dropdown value to the server side
e.preventDefault();
var fleet = document.getElementById("Fleet").value
document.getElementById('photostatus').innerHTML = "Waiting For Photo.."
if(fleet != "Not on this list?"){
var data1 = {
FleetNumber: document.getElementById("Fleet").value,
}
google.script.run.withSuccessHandler(consoleyay)
.sendFleet(data1)
}
else if(fleet == "Not on this list?"){
console.log("right area")
document.getElementById("Rego").innerHTML= "Rego"
document.getElementById("NOLF").style.display=""
document.getElementById("NOLR").style.display=""
document.getElementById("NOLB").style.display=""
document.getElementById("NOLS").style.display=""
document.getElementById("Fleet").style.display="none"
document.getElementById("Rego").style.display="none"
}
}
function SENDFLEET(e){ // This code sends a user entered value to the server.
e.preventDefault();
var fleet = document.getElementById("NOLF").value
document.getElementById('photostatus').innerHTML = "Waiting For Photo.."
var data1 = {
FleetNumber: document.getElementById("NOLF").value,
}
google.script.run.withSuccessHandler(consoleyay)
.sendFleet(data1)
}
function sendFleet(data1){
var Fleet = data1.FleetNumber
var FleetListing = SpreadsheetApp.openById("1ufyN6mgzdHXoYbVC6TENcc7V2zGxdQtp0ctaCR-kiEw").getSheetByName("FleetListing")
var data2 = FleetListing.getRange(3,3,FleetListing.getLastRow(),1).getValues().reduce(function (a, b) { //flatten the 2D array obtained by .getValues()
return a.concat(b);
});;
var fleetdata = FleetListing.getRange(3,1,FleetListing.getLastRow(),8).getValues()
var Search1 = data2.indexOf(Fleet)
var site = ""
var type = ""
var fleet = ""
var rego = ""
var insidev = ""
var outsidev = ""
var insideb = ""
var outsideb = ""
var search = ""
Logger.log(Search1)
if(Search1 != "-1"){
Logger.log("shouldn't be here")
site = fleetdata[Search1][0]
type = fleetdata[Search1][1]
fleet = fleetdata[Search1][2]
rego = fleetdata[Search1][3]
insidev = fleetdata[Search1][4]
outsidev = fleetdata[Search1][5]
insideb = fleetdata[Search1][6]
outsideb = fleetdata[Search1][7]
search = Search1
}
else if(Search1 == "-1"){
var MTL = SpreadsheetApp.openById("1ufyN6mgzdHXoYbVC6TENcc7V2zGxdQtp0ctaCR-kiEw").getSheetByName("MasterToLocal")
var data3 = MTL.getRange(1,3,MTL.getLastRow(),1).getValues().reduce(function (c, d) { //flatten the 2D array obtained by .getValues()
return c.concat(d);
});;
var fleetdata1 = MTL.getRange(1,1,MTL.getLastRow(),8).getValues()
var Search2 = data3.indexOf(Fleet)
Logger.log("lukes okay")
Logger.log(Fleet)
Logger.log(Search2)
Logger.log(data3)
if(Search2 != "-1"){
Logger.log("Test start")
site = fleetdata1[Search2][0]
Logger.log(site)
type = fleetdata1[Search2][1]
fleet = fleetdata1[Search2][2]
rego = fleetdata1[Search2][3]
insidev = fleetdata1[Search2][4]
outsidev = fleetdata1[Search2][5]
insideb = fleetdata1[Search2][6]
outsideb = fleetdata1[Search2][7]
search = Search2
Logger.log("Test Finish")
}
}
return [site,type,fleet,rego,insidev,outsidev,insideb,outsideb,search]
}
function consoleyay(details){ // this is the code that handles the response from the server.
console.log(details)
var site = document.getElementById("Site").value
console.log(site)
console.log("issues 1")
var Type = document.getElementById("Type").value
console.log("issue 2")
var fleet = details[2]
var rego = details[3]
var inv = details[4]
var outv = details[5]
console.log("before bg")
var inb = details[6]
var outb = details[7]
console.log("after BG")
var Search1 = details[8]
Solved the issue. Instead of using .getValue, i used .getDisplayValue which will return the date as a string.

Get Last email from thread and fetch csv attachment

I an trying to get last email thread csv attachment ID but I am having difficulties working out the code. Anyone able to help?
var searcher = "Automail-"+CurrentDateFormat+".csv";
var searchedThreads = GmailApp.search( 'subject:""'+searcher+'""')[0];
var id = searchedThreads.getId();
var dateMessage = GmailApp.getMessageById(id).getDate();
var contentmessage = GmailApp.getMessageById(id).getPlainBody();
var attachtextLength = GmailApp.getMessageById(id).getAttachments()[0].getDataAsString().length;
if (attachtextLength >= 150){
var attachtext = GmailApp.getMessageById(id).getAttachments()[0].getDataAsString();
UpdateSheet(attachtext);
If you are looking for the last thread matched of multiple threads....
var searchedThreads = GmailApp.search( 'subject:""'+searcher+'""');
searchedThreads = searchedThreads[searchedThreads.length-1];
If you are looking for the last attachment ....
var attachtext = GmailApp.getMessageById(id).getAttachments();
attachtext = attachtext[attachtext.length-1].getDataAsString();
Hope it helps.

Parsing XML Data that I receive from UrlFetch

I want to parse the data I get from UrlFetch into a spreadsheet, but all I'm getting is undefined can someone show me what i'm doing wrong
The xml is at the address https://dl.dropbox.com/u/11787731/Minecraft/bans.xml
function runevery15mins() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("MC Bans");
sheet.clearContents();
var banURL = "https://dl.dropbox.com/u/11787731/Minecraft/bans.xml";
var banXML = UrlFetchApp.fetch(banURL).getContentText();
var banDOC = Xml.parse(banXML, false);
var mcuser = banDOC.bans;
var x = 0;
for(var c=0; c>mcuser.length;c++){
var name = mcuser.getElement("username")[c].getText();
var date = mcuser.getElement("date")[c].getText();
var reason = mcuser.getElement("reason")[c].getText();
var duration = mcuser.getElement("duration")[c].getText();
}
sheet.appendRow([name, date, reason, duration]);
}
You have some small errors in your code.
For example, the second argument in the for loop needs to be c<mcuser.length.
Using the Xml service documentation, this worked for me
function runevery15mins() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("MC Bans");
sheet.clearContents();
var banURL = "https://dl.dropbox.com/u/11787731/Minecraft/bans.xml";
var banXML = UrlFetchApp.fetch(banURL).getContentText();
var banDOC = Xml.parse(banXML, false);
// Get all the child nodes from the document element that are 'user' nodes
var mcusers = banDOC.getElement().getElements('user');
for(var c=0; c<mcusers.length;c++){
var user = mcusers[c];
var name = user.getElement('username').getText();
var date = user.getElement('date').getText();
var reason = user.getElement('reason').getText();
var duration = user.getElement('duration').getText();
sheet.appendRow([name, date, reason, duration]);
}
}
Note for example that the sheet.appendRow line is INSIDE the loop, not outside as you had it before. I also deleted the X variable, since I didn't see any purpose for it.
I also created a user variable, which is an XmlElement, to make it easier to understand how to get the different contents of each node.
You were almost there.
Looks like there was another array you needed to drill down into. Also, your call back to the spreadsheet should be in the loop. Try this:
...
var mcuser = banDOC.bans.user;
for(var i in mcuser){
var name = mcuser[i].getElement("username").getText();
var date = mcuser[i].getElement("date").getText();
var reason = mcuser[i].getElement("reason").getText();
var duration = mcuser[i].getElement("duration").getText();
sheet.appendRow([name, date, reason, duration])
}