Get value of textbox in a table (GAS) - google-apps-script

I know that this is something discussed sooo many times, but I can't get the value of a textbox that is placed in a table. I know how to get the value of a textbox (e.parameter.textBoxName), usually it's working without any problems.
The only difference now is that I have a gadget containing 5 tabs, each with some intro text and a table. Each table contains approximately 30 rows, each with two textboxes and a button to submit the value of two textboxes in the specific row to a spreadsheet. Everything is working fine, all the names (and IDs as well) are unique, but the problem is that when I submit textboxes, I get "undefined" (in my spreadsheet).
I guess the problem lays somewhere in the complexity of the script, so this:
function buttonClick(e) {
var app = UiApp.getActiveApplication();
var theValue = e.parameter.textBoxName;
...something...
}
..is simply not enough to define which textbox it is. However I'm getting the button ID without any problem with
var buttId = new String(e.parameter.source);
I'm trying to get my head around this for a couple of days without any results. I'm not that good with GAS and I'm completely out when it comes to objective programming. Do you have some ideas how to get this value? I can get the ID of the table if that helps, but what to use then?
Thank you very much in advance!
EDIT:
I tried .addCallbackElement(textbox) to the textbox - I'm getting an error. I tried .addCallbackElement(textbox) to the submit button together with .addCallbackElement(button) and I'm still getting "undefined".

the callbackElement must be added to the handler, not to the widget nor to the button.
The easiest (and safest) way to get it done correctly is to choose the highest level parent as callbackElement.
I your case it would probably be the tab panel or eventually another panel that contains your 5 tabs if you used one.
Note also that there might be really a lot of widgets in the same UI without causing any issue... I have an app with about 200 textBoxes that works flawlessly and I'm not aware of any limit nor if a limit even exists...

Related

Is there any way to make it so that a cell can only be changed once in Google Sheets?

I have a Sheet which I would like to use as a simultaneous sign up for many people for timeslots for an event. We have noticed that what can happen is users erasing each other's entries in the sheet. Ideally we would like to make it so once someones name is entered for a timeslot it cannot be removed by other users.
I've tried to use data validation to reject certain criteria, but I've only managed to get it to reject a cell changing from blank to a non-blank value. Which I achieved with the following:enter image description here. But I'd like the opposite behaviour, with some additional functionality
Changing the formula to NOT(ISBLANK(B2)) doesn't seem to put any restriction on the cell at all as hitting backspace or delete on cell seems to clear the contents without ever considering that an input to check. Changing the value never causes the cell to go blank so it doesn't seem to affect changing either. I'm really at a loss as to how to do this and any help is appreciated. I'm open to solutions which use VBA or other programming languages to get the desired result as well.

Selecting/highlighting next adjacent cell in row after function has been executed in google script

I am not really experienced with coding so I apologize in advance if this is a stupid question with an obvious answer...
I use a google sheet to keep track of things at work, and my employees use it multiple times a day. They will either type one of three phrases into a certain cell on a row, so I have created buttons using the drawing feature that they can simply click, which will insert the appropriate text into the highlighted cell.
Once this text is inserted into the cell, I would like to add something to the end of the function that automatically selects the next adjacent cell in the row (to the right) so they can continue typing in. Currently, once they click the button to insert text into one cell (e.g., B23) they have to use the mouse to manually select C23 before typing into that cell. For some reason you cannot use the right arrow key or tab key on the keyboard to move over, so I am wondering if there is a way to add the selecting process into the script (or even a workaround for allowing the tab or right arrow keys to work).
I realize this may seem like a tedious question and folks may think it is awfully lazy of me to ask for a more efficient way to move over to a cell than using the mouse, but my employees use the sheet hundreds of times a day, so I'd really like to maximize the efficiency for them to make it as easy and convenient as possible. Inputting data can be tedious enough, so I am trying to simplify things and make it as least painful as possible :)
Thanks so much!
There are several ways to select the cell at the right. One way is to use offset(rowOffset,columnOffset):
range.offset(0,1)
You are correct. When using a button the focus stays in the button when it is clicked. After some trial and error, I think I found a way that will work fot you. I created a html sidebar that is opened from a custom menu. Once opened, you can leave it opened, HTML allows control over the focus using 'google.script.host.editor.focus()'. Then you can type in the cell. Attached is my sample spreadsheet you can copy and try. Let me know if you need any help changing the button names or text. Sorry my first try didn't work correctly. https://docs.google.com/spreadsheets/d/1KlNSJnZDNIb2chUK3SlKJg79VNIrsAbIbUvHyLwTLWk/edit?usp=sharing

Google scripts unhideRows not working

I have a script for Google Sheets I am working on. I realize there are better ways to do what I am attempting (cough html/database cough), but I am required to make this spreadsheet work.
In short, I am trying to hide and unhide rows dynamically. There does not appear to be a way to get filters to update without redoing them, so I am attempting to use hideRows to hide them and unhideRows to reveal them as needed.
The hideRows command works below. The unhideRows command does not. At this time, they are literally this close together in the code. Originally, I was hiding on one sheet and unhiding on another, but set up like this to troubleshoot. There is no filtering on this sheet (because it didn't work, I turned it off). I tried setting the value in unhideRows directly to the value tested instead of a variable.
The row in question hides, but does not unhide.
I tried unhiding a different row just in case google was fumbling with hide this, unhide it back to back. I am not getting unhide to work.
{ //thisRow = the row number of a range, in this case 2 if output to screen
pImages.hideRows(thisRow);
pImages.unhideRows(thisRow);
}
Apparently, the answer is not to unhideRows() which is the one the documents alluded to, but showRows () which does make more sense in everyday language. Thanks again to Mr.Houdini on the Google forums.

Retrieving form value with jQuery

Sadly, this isn't as cut and dry as I had hoped. Over the past few weeks I had been researching the use of jQuery with CRM. While it's nice and dandy for style alterations, I couldn't find any examples that are closer to business logic.
For example, today I needed to alert the browser if one of 4 fields were empty. Two were date fields, one a picklist and one a checkbox (bit). I thought that calling $("#formElement").val() would have gotten the value, and in some cases it did, such as the picklist after I parsed it as an int. However, the date fields always returned an empty string.
Looking through the CRM form HTML, I see that "#formElement" isn't always the ID of an input for a CRM form element. Case in point, the date fields had ID="DateTime" (or something similar). At this point, I had thought that I will need to create a filter that will take the table that contains #formElement as it's ID and look for the value of the first input in that table, but at that point using crmForm.all.formElement.DataValue just seemed easier.
I'm sure someone here has a solution for this (and maybe some explaination of how CRM Forms are written to help with a filter), and it really stinks not being able to install add-ons for Internet Explorer here at work. Thanks for any and all help.
Use jQuery to select the form itself (either by its ID or just by $(form)) and then iterate over its children that are input text fields. I haven't done this for a form before but it might work for you.
For anyone else who is looking for an answer, I have figured it out to a managable degree. Unfortuantely, I haven't been able to use CSS selectors to shorten attribute names, but I have been able to utilize jQuery to cut down on time. If you'd like to use a CRM 4 attribute with jQuery, it looks like this:
$(crmForm.all.new_attribute).bind("click", function() { ClickFunction(); });
What I was really gunning for was chaining, because there are plenty of times when I need to null a field, disable it, and then force it to submit. A little bit of magic and this:
crmForm.all.new_attribute.DataValue = null;
crmForm.all.new_attribute.Disable = true;
crmForm.all.new_attribute.ForceSubmit = true;
Becomes:
crmForm.all.new_attribute.dataValue().disable().forceSubmit();
I hope this helps some of you guys out!

Rendering 20 large identical listBoxes

I have an HTML table with rows (20 rows).
Every row has a listbox of countries (about 250 countries) that are filled using a single dataset from the database.
Loading time is quick enough, but rendering time is really a mess.
Is there any way I can speed the rendering of those listboxes?
You could load it only once, and then copy the DOM element everywhere you need it...
I'm not sure if this would improve a lot since it would rely more on the user's computer, but I guess it's worth trying if it's too slow the way it is right now.
edit: here's how I'd do it. Use with caution, I haven't tested it and there is most likely tons of errors with this code, it's just to give you an idea of what I was saying.
<mylistbox id="listboxtemplate"> ... </>
<div class="thisPlaceNeedsAListbox"></div>
<div class="thisPlaceNeedsAListbox"></div>
<div class="thisPlaceNeedsAListbox"></div>
on document ready, using jquery:
jQuery(".thisPlaceNeedsAListbox").append( jQuery("#listboxtemplate").clone() )
You could try to add next select box only after user has selected previous one (using JavaScript).
I'm quite sure that you can rethink the form or the process, but I can't suggest anything specific since you haven't given enough information. For example depending on situation you could use multi-select or some fancy JavaScript widget.
EDIT based on your comment:
Then how about serving the table without selects. And if user double clicks on a country field you change the text element to select element using javascript. And once user has selected the country you can change back to text element. You can submit results back to server using Ajax (after user has selected the country) or using hidden fields a submit button. This way DOM will never contain more then 1 select element.
You can pass countries to javascript using inline JSON object/array (in script tags). To make things even more faster after user has edited the first element, just hide (css: display: none;) the first build select element and clone/move it around each time user wants to edit a row.
As you can see there are a lot of paths you can take using this approach, it all depends how much you want to optimize/work on it.