I am writing a script that will use a table that a user has selected. However, using DocumentApp.getActiveDocument().getSelection().getRangeElements() will get only the individual cells. I thought I could just reconstruct the table, but the cells are all in one long list with no info on rows or columns, and the user should be able to select a table of any height/width without having to tell the program what the dimensions are. I also thought about having the program automatically select a bit ahead, in order to treat the table as a table and not individual cells, but this still selects individual cells (but not all of them which is a bit peculiar.) Thanks for any feedback/help!
Replacing a table selected by placing cursor in any cell
I just made up a two dimensional array for the table to be replaced with.
If you try to cast the first element asTable() you'll get the error 'PARAGRAPH can't be cast to TABLE.' then if add another getParent() you'll get the error 'TABLE_CELL can't be cast to TABLE. ' and then add another getParent() and you'll get the error 'TABLE_ROW can't be cast to TABLE.' and finally adding yet another getParent() finally passes through the gauntlet and replaces the the table. You can put the cursor in any cell in the table. It was a bit of a hack but in the end it seems to work. It would have been much more difficult to figure this out without knowing how to use the debug resources that Google provides.
function replaceTableAtCursor(){
var doc=DocumentApp.getActiveDocument();
var body=doc.getBody();
var el=doc.getCursor().getElement().getParent().getParent().getParent();//element/cell/row/table
var table=el.asTable();
var t=[];//This is the table I used. Any 2D array will work like the ones you can get from getValues() method from spreadsheets.
for(var i=0;i<3;i++){
t[i]=[];
for(var j=0;j<3;j++){
t[i][j]=Utilities.formatString('i:%s,j:%s',i,j);
}
}
var childIndex=body.getChildIndex(el)
table.clear();
body.insertTable(childIndex,t)
}
Position Class
Trouble Shooting
Example That Edits a Table in Place
Related
I am have been trying to find a solution to my google sheet issue and have tried quite a few workarounds thus far, to no avail. I imagine I may need to use javascript to do the action, however, I am a beginner to javascript.
Here is what I would like the sheet to do.
Check 'sheet#2' and see if an item in the specified range is set to "out-of-stock"
Sheet#2
If the item in the range is set to "out-of-stock", then remove the item from the data validation list on 'sheet#1' and if it is "in-stock" then show the item on the data validation list.
Sheet#1
Here are some things I have tried thus far (if it helps):
on sheet#2 when an item is set to out stock, conditional format it, to make the cell text white (not visible). This works well for that particular sheet. however, data validation lists do not display the data it pulls exactly as it appears (so the text still shows on the dropdown list)
IF statement. I've tried a WHOLE LOTTA IF and IFS statements. This did not work, because you cannot have an if statement in the same cell as a data validation cell and b/c the cell name will likely need to be constantly changed in the future. (But I did, however, find a workaround to another issue I was trying to solve for a day now WHOOP WHOOP!)
Oh and I also tried conditional formating the cell so that if it ='s out of stock white out the cell... however I get an error that conditional formatting does not work across 2 sheets
... so yeah if anyone may know of a solution to get this to work I will forever appreciate it! I'll keep scouring google for solutions in the meantime.
For the sake of simplicity, I've created a sample spreadsheet with two sheets: Sheet 1 and "Stock".
Sheet 1
Stock
Solution
I've created an Apps Script function to set the Data Validation as you have specified.
I've used the Javascript filter and map functions to simplify getting the data, but basically:
I get all the rows from the Stock sheet and load them into "memory"
I then discard from "memory" the rows that do not have their second column (row[1]) equal to "In Stock".
Then I get the remaining rows and grab only their first column (row[0]).
I then create a new DataValidation object (with it's builder) that uses the list we got above and assign it to the range I want to have validated.
//VARIABLES
var rangeToValidate = "B2:B";
var validateSheet = "Sheet1";
var optionSheet = "Stock";
function refreshDataValidation() {
var inStockOptions = SpreadsheetApp.getActive().getSheetByName(optionSheet).getDataRange().getValues()
.filter(function (row) { return (row[1]=="In Stock")})
.map(function(row) {return row[0]});
SpreadsheetApp.getActive().getSheetByName(validateSheet).getRange(rangeToValidate)
.setDataValidation(
SpreadsheetApp.newDataValidation().requireValueInList(inStockOptions).build()
);
}
Also, by adding some code with Apps Script, the sheet will make sure that your drop-down is always up-to-date.
I am refreshing the drop-down every time the sheet is opened and every time there is an edit to the Stock sheet on the B column.
//When the sheet is opened, refresh the data validation
function onOpen(e) {
refreshDataValidation();
}
//When a change is made to the Stock sheet, also refresh validation
function onEdit(e) {
var range = e.range;
if (range.getSheet() == SpreadsheetApp.getActive().getSheetByName(optionSheet) && range.getColumn() == 2) {
refreshDataValidation();
}
}
Hope this helps!
Okay guys I found a solution, anyone visiting this post in the future here you go!!!
So yes, you can use the script as provided above. However, if you already have other scripts, data validations, and other formatting's going then ,like me, you may actually run into a lot of errors and conflicting issues.
As a workaround here is what I did to get everything to work properly. you will need a total of 3 sheets: a main sheet, a 2nd sheet with your options, and a 3rd sheet to house the pulled data.
On the 2nd sheet, be sure to have a column that shows if the item is "in-stock" or "out-of-stock" (I did it as a dropdown menu)
On the 3rd sheet select the cell where you would like the data to show. And use the filter function formula to pull only the rows from sheet 2 that are equal to "in-stock"
Formula syntax: =(FILTER (range, condition1, [condition2, ...])
My Formula: =FILTER( sheet2!G3:R5, sheet2!I3:I5 <> "out-of-stock")
sheet2!G3:R5 = the range of rows/columns I want it to pull from.
sheet2!I3:I5 = the column I would like it to look for the words "in stock" or "out of stock" in
<>"out-of-stock" = show me the data if a cell in column I3 does not equal "out-of-stock" (meaning, only show in-stock options)
As you can see the formula will pull/show you all the rows that = "in-stock", anything you have set to "out-of-stock" will not show on the 3rd sheet.
Last part,
On the main sheet select the column you would like for your drop down list to show in. Add the data validation being sure to list from the range on the 3rd sheet (not sheet 2).
Now you can hide the 3rd sheet as you should no longer need it, unless debugging.
Finally, As you can see now, my main sheet will only show the items in the drop down list that are set to "in-stock", out of stock options are removed from drop down list, unless set back to in-stock. (see how pic3 only shows 2 options in drop list, although pic1 shows that there are 3 options available).
so now basically if I change an item to "out-of-stock" on the 2nd sheet, the item will be removed from drop-down list on the main sheet, AND if I change an item to "in-stock" the item will be added/displayed on the drop list. The 3rd sheet is no longer needed. This solution is perfect if you have multiple users and would only like for them to be able to select an option that is "in-stock"!
Hope this helps someone!!! And thank you to the people of above who gave other possible solutions!!
I've to create a table with a row of input boxes.
The values entered in will then be multiplied by script and the answer placed in the last input box, the row total, if you will.
There is a button above the table to add another row.
Each time a row is added, the same input boxes need to appear, and the same 'row script' to calculate the row total.
Once a particular row has been added/updated, and it's row total calculated, a final number needs to be found, which is essentially the total of the row totals. Let's call it the column total.
My skills aren't super high, am learning as I go, especially from the decent responses this site seems to attract. One hopes this is at least understandable....
I've managed to get row to be added by a button using table.insertrow, and the scripts for doing the math are no problem. I have also managed to use a simple loop to create the dynamic variable names for each input box; named the same and numbered by row.
Where I'm stuck is generating the scripts to totalise a line and then another tot totalise the table, as the script needs to factor in how many rows there are, and I can't see how to write this except using Eval() (so far..).
I've also experimented a little with this and each but just got bogged down and could no longer see the logical flow.
What I've written to date is now just a mess.
Instead of posting code for comment/fix, I seek to better understand which way to address the problem using Javascript if at all possible, hopefully without using Eval().
Any suggestions would be welcomed by this brain-dead, gone bleary, wishing he hadn't started, noob.
UPDATE: Have seen a lot of ways to use JQuery, but it's not for me at the moment.
perhaps phrased differently - how in javascript would you loop through a table column, adding up all of the cell contents (numbers) in that column, please. I can't seem to figure out how to use Each as the variable names are different (numbered) per row.
Something like this:
var tr = document.createElement("<tr>");
var td = document.createElement("<td>");
tr.appendChild(td);
You have to create table row, fill it with cells, cells with buttons and so on. As result you will have table row variable which you can insert every time your button clicked.
I know that the practice is that every element has a unique id. I am curious about this case: I have a table (let's call it table1) that has many functions connecting its cells in various ways (ex: editing one cell changes other cells accordingly). Now, I need to have another table (let's call it table2), that will have exact same functions between its cells.
I would like to avoid changing the ids in the table2, and then copy pasting the js functions for the table1 and apply them for the ids from the table2.
The easiest thing for me would be to just copy-paste this table1 (so the cells in the table1 and table2 will have same ids), and adapt the js functions to make sure that whenever a change in table1 happens - only table1 is affected, and not cells in table2, and vice versa.
Example:
$('body').on('keyup', "input[id^='sub_']", function() {
$("[id^='top_']").val(5);
}
Now, I suppose if I have an id that begins with "top_" in both tables that the change in table1 will also change the value of the field "top_" in table2.
How can I make sure to avoid this?
I was thinking to do something like this:
$(this).closest("input[id^='top_']");
But this is not working, the values are changed in both tables... Does anyone have a suggestion?
Try the following code snippet:
$(this).closest("table").find("input[id^='top_']");
This will make sure the changes are made only within the table where the event occurred.
EDIT
Here is a small example that you can modify for your needs if you don't want to provide your HTML: https://jsfiddle.net/fjh0v6m4/10/
Maybe try
$('#sameid')[0].dosomething()
I have a container that contains data populated from my database as well as data created by the user on another page.
My issue is styling. Currently my page jumbles and the columns are all over the place. They appear to be following the end of the longest column.
Jumbly
I would like for after 3 columns a new row to be created, but I'm not sure how to go about this.
Note/Tricky part:- My users have the option to sort where each Column (Sales, BingBong, Game of Thrones) goes. If they want Game of Thrones first, they can make it the first column. Obviously this messes things up because each column will have a different height at different times
Most everything I've seen squishes all the columns together to create a pinterest-like look. That is not what I want and I know that my design will create white space. That is what I'm being told to create.
UPDATE: Here is my code to show you how I iterate through each of these departments (sales, rainbows n'sprinkles, Game of Thrones, etc).
Hopefully this makes it clear why adding a clearfix div doesn't work in my case
code
http://www.codeply.com/go/jXuoGHHker
This worked brilliantly!!! Works with dynamic data...all I grabbed were the few lines of CSS
I have an application (using SlickGrid) where I need to get the column name or id at any time when user clicks on a cell (this pulls up a menu specific to the data in that column/cell). Grid works fine initially but if the column is moved (drag/drop), the column name/id does not follow the drop but remains mapped to it's initial column position.
Has anyone else seen this and, if so, how did you fix it?
Thanks
Are you trying to reuse the list of columns defined in your html code? You should get the list of columns from the grid instead. The following code should do what you are expecting (i.e. printout the name of the column in which you clicked a cell):
grid.onClick.subscribe(function(e,args) {
var allColumns=grid.getColumns();
console.log(allColumns[args.cell].name);
});
You can add that code in one of the examples provided with the source code (say "example3-editing.html"), drag-drop some columns around and check the console after clicking on a cell.