I want to Remove an item from a list once chosen in the dropdown and then the next dropdown won't have that item anymore. I've already made something manually but it takes super long and is not really ideal because you would need to go down in order otherwise it gets all mixed up.
https://docs.google.com/spreadsheets/d/1o3J1ZXzxQL11pdN1FDOQZ7YXbSib6A8KwkxBzO5bSM0/edit?usp=sharing
I've made 3 tabs one where I explain what I want and the other were I made it manually so you have an idea on how it works. But remember the manually one you need to go down in order. I want for it to look at a range so it doesn't matter which dropdown I choose for it to get removed from the list.
If it isn't possible to do it by range then like the same way as manually but then in script form would be a great help as well.
Here is what I tried but I'm really new with scripting so I might not even be close:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Dropdown');
//get's the value in range A1 ( the firstdropdown value )
var firstDrop = ss.getRange("A1").getValue();
//get's the value in range A3 ( the seconddropdown value )
var secondDrop = ss.getRange("A3").getValue();
//get the list ( I don't want to put the list in here sincec I'll be
//working with entries from google forms. so the list will be changing)
var list = ss.getRange("H1:H5").getValues();
if(firstDrop == list){
var newlist = (list-firstDrop);
}
}
This may work for you - I think it gives you the result you want, but its appearance isn't ideal. I've placed it into your sheet, in the last tab. I believe that this is the same approach as Mateo's earlier answer, but down with a formula instead of code.
=SORT(FILTER(B2:B;NOT(COUNTIF(A2:A;B2:B))))
where A is the column where you are entering data, and B has your list of valid names/words.
I use this formula to filter the list of words/names that show in each dropdown list. It starts with the original list, and excludes any that have already been selected. The data validation for your cells points to the filtered list, not the original list.
The drawback is that once you select a word/name, it is no longer eligible for the dropdown cells, so even the cell where it has already been applied shows it as an invalid entry, with a little red triangle. The benefit of a working solution may outweigh this though.
I believe it should look like this:
function availableSlots(){
var form = FormApp.openByUrl('URL_OF_YOUR_FORM'); // TODO add your form url
// need to read what slots are available
var slots = SpreadsheetApp
.getActiveSpreadsheet()
.getRange("slots!A2:C10")
.getValues(); // TODO make sure getRange matches your quota range
var choice = [];
// loop through our available slots
for (s in slots){
// test if slot still available
if (slots[s][0] != "" && slots[s][2] > 0){
choice.push(slots[s][0]); // if so we add to temp array
}
}
var formItems = form.getItems(FormApp.ItemType.LIST); // our form list items
// TODO assumption that first select list is the one you want to change
// change formItems[n] if you have more than one select list
// and we just rewrite all the options to ones that are free
formItems[0].asListItem().setChoiceValues(choice);
}
As I was not sure which dropdown menus you wanted to use I have created a sample sheet with your requirements (photo attached below). In order to reduce the list of items in function of the output of the rest of the dropdowns I have used on onEdit() trigger to check for any changes in these dropdowns and in function of these cell values remove the required items from the list.
The following piece of code has self explanatory comments that address how I have implemented this:
function onEdit(e) {
// Get sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('Share your Ideas here :)');
// Get list from range. Flat will make the 2D array returned by getVaues() into a 1D array
var list = sheet.getRange("E1:E5").getValues().flat();
// Get values from the dropdowns
var a = sheet.getRange("A1");
var b = sheet.getRange("B1");
var c = sheet.getRange("C1");
// Check if any of the values in the dropdowns match the list and if so remove them from
// the list
var index = list.indexOf(a.getValue()); if(index != -1){list.splice(index,1);}
index = list.indexOf(b.getValue()); if(index != -1){list.splice(index,1);}
index = list.indexOf(c.getValue()); if(index != -1){list.splice(index,1);}
// Create the data validation rule with the filtered list
var rule = SpreadsheetApp.newDataValidation().requireValueInList(list).setAllowInvalid(false).build();
// Create/update the dropdowns with the right filtered list
a.setDataValidation(rule);
b.setDataValidation(rule);
c.setDataValidation(rule);
}
References
Data Validation
requireValueInList
Related
In flutter I'm trying to have one of the columns of a DataTable be a DropdownButton. I would like the DataTable rows to populate from getUsers initially, then be able to edit the cell cell with a the DropdownButton based on the ratingList.
So I would like to be able to change the value of the DropdownButton cell to any of the values in the ratingList: ['Ok', 'Good', 'Great', 'Amazing']; Note I want to be able to select 'Great' or 'Amazing', these aren't one of the initial populated values.
It is essential for the data to be loaded from getUsers, as this will be grabbed from Firestore eventually. Then have the ability to change a DropdownButton cell after the data is loaded, based on the ratingList of values, which is a complete list of the ratings.
See below for example code (DropdownButton doesn't change cell value), also in DartPad.
Thanks in advance!
Just put user.rating = newValue into setState block.
Like this.
onChanged: (String newValue) {
setState(() {
//help!
user.rating = newValue;
});
},
I have a shuttle list that, depending on the selection of a previous form, may have between one and seven items. Is there any way for me to automatically move the entry to the right hand pane if there is only a single selection, just for the sake of long term optimization and user friendliness?
You can add a default Value to your shuttle item
SELECT YOUR_COLUMN_ID
FROM T0000_YOUR_TABLE
WHERE FILTER_COLUMN_ID = :P_FILTER_ITEM_PREV_FORM
GROUP BY YOUR_COLUMN_ID
HAVING COUNT(*) = 1
If there are more than 1 entries for your filter item the statement will return nothing, if there is exactly 1 entry the entry will be returned and set for your shuttle item
I like sim0n's answer. But here's another that uses JavaScript (you can choose which is best for your use case).
Create a Dynamic Action. Set Name to Page loaded and Event to Page Load.
Select the Action created by default. Set Action to Execute JavaScript Code, then enter the following code in Code.
var itemId = 'P1_ITEM_NAME';
var $opts = $('#' + itemId + ' select:eq(0) > option');
if ($opts.length === 1) {
$s(itemId, $opts.val());
}
Don't forget to change the name of the item to match the one on your page.
When the page loads, the JavaScript will check to see how many options are in the select element on the left. If there's just one, it will set the value of the item using the value to the value of the single option.
I have two region one form and one interactive grid like a master detail(company and company contact person ) how i can make the interactive grid mandatory ,the user can't submit page ,he/she need add at least one row in interactive grid ,
I can do that or I need to change the interactive grid to collection and count the row in validation
This one is a little tricky because of the way processes and validations work with Interactive Grids (they are executed once per submitted row). To work around this, I'll use a page item and a validation that works with it.
The basic idea of this solution is based on the fact that a new row will not have a primary key value. Here are the steps to reproduce (my example was on page 14, update the following as needed).
Create an Interactive Grid (IG) region. The primary key column should be Query Only (which ensures it's null for new rows).
Create a Hidden page item named P14_NULL_FOUND. Set Type under Server-side Condition to Never so that it never renders on the page.
Create an After Submit (before Validations) process. This process will NOT be associated with the IG so it will only fire once. Set the PL/SQL Code attribute to:
:P14_NULL_FOUND := 'NO';
That will clear out the value of the page item prior to the next process.
Create another After Submit process that runs just after the previous one. Set Editable Region to the IG. Then set the PL/SQL Code to something like the following:
if :PK_COLUMN_IN_IG is null
then
:P14_NULL_FOUND := 'YES';
end if;
You'll need to replace ":PK_COLUMN_IN_IG" with the name of the primary key column in the IG, such as ":EMPNO". This process will be run once for each submitted row in the IG. If a null value is found for the primary key column, then that would mean the user added a new row and the value of P14_NULL_FOUND would be set to 'YES'.
Create a new validation. This validation will NOT be associated with the IG so it will only fire once. Set Type to PL/SQL Expression. Set PL/SQL Expression to:
:P14_NULL_FOUND != 'NO'
Then set Error Message to something relevant.
At this point, you should be able to run the page and verify that the processes and validation are working correctly.
There is an another solution;
Create a page item like PX_ROWCOUNT which will hold the data of the row count of your IG.
Assign a static ID to your IG region.
Write a JS function to count the rows of the grid then set it to the page item. Sample function;
function f_setRowCount(){
var grid = apex.region("staticIDOfYourIG").widget().interactiveGrid("getViews", "grid");
var model = grid.model;
var rowCount = 0;
model.forEach(function (record) {
rowCount ++;
});
$s("PX_ROWCOUNT",rowCount);
}
To submit your page and run this function, change your submit button's behavior to Defined by Dynamic Action. Execute your function when user clicks to that button then submit your page via DA.
Add validation to Processing section of the page and check your page item there; PLSQL Expression => :PX_ROWCOUNT > 0
The solution by Hamit works nicely, except of the case of deletion of a row.
My suggestion is to amend the above code by adding inside the loop an if statement to check whether the row is editable or no.
So the code will be
var grid = apex.region("staticIDOfYourIG").widget().interactiveGrid("getViews", "grid");
var model = grid.model;
var rowCount = 0;
model.forEach(function (record) {
if (model.allowEdit(record)) {
rowCount ++;
}
});
$s("PX_ROWCOUNT",rowCount);
I have an interactive grid with a bunch of records, and I want to set up a button on the page that changes one column in all records currently selected.
Running APEX 18.2, the IG has a whole bunch of columns and I want to change just one of them, but on a whole bunch of rows, so I do need a button.
The IG has ROWID as PK because the actual PK is assembled from 4 different columns.
I have spent some time googling this issue and have found a couple people with solutions:
http://thejavaessentials.blogspot.com/2017/03/getting-selected-rows-in-oracle-apex.html
This is the first, and simplest solution. But it doesn't return any rowid or anything like that, it returns the value in the first column.
Then I also found
http://apex-de.blogspot.com/2018/09/update-several-rows-in-tabular-form-grid.html
and
https://ruepprich.wordpress.com/2017/03/23/bulk-updating-interactive-grid-records/
Which are pretty similair and seem to be the best for me, but I get a Javascript error in the console: http://prntscr.com/n5wvqj
And I dont really know much Javascript, so I dont know what went wrong or how to best fix it.
I set up a Dynamic action on button click that executes Javascript and I have the selected element being the region named CUR_STAT.
var record;
//Identify the particular interactive grid
var ig$ = apex.region("CUR_STAT").widget();
//Fetch the model for the interactive grid
var grid = ig$.interactiveGrid("getViews","grid");
//Fetch the model for the interactive grid
var model = ig$.interactiveGrid("getViews","grid").model;
//Fetch selected records
var selectedRecords = apex.region("CUR_STAT").widget().interactiveGrid("getViews","grid").view$.grid("getSelectedRecords");
//Loop through selected records and update value of the AVT_OBR column
for (idx=0; idx < selectedRecords.length; idx++)
{
//Get the record
record = model.getRecord(selectedRecords[idx][0]);
// set Value for column AVT_OBR on "D"
model.setValue(record,"AVT_OBR", 'D');
}
The column named AVT_OBR is a select list with display values(DA, NE) and return values(D, N). But I tried having it be a text field and it didnt help.
I want to be able to select multiple columns and change the data in those entries.
If possible I would also like to be able to change data in such a way in a hidden column. Or if I could get all the ROWIDs for selected records and execute a PLSQL block with them.
Ended up with noone responding so I spent a lot of time and finally came up with a solution.
var g = apex.region('myIG').widget().interactiveGrid('getViews','grid');
var r = g.getSelectedRecords();
for(i = 0; i < r.length; i++) {
g.model.setValue(r[i], 'myColumn', 'Value');
}
For some reason none of the solutions I found had worked. But I learned from those solutions and made this simple piece of code that does what I need.
Also, I was wanting to set up so I could do this set value on a hidden column, I achieved this by just having the column visible and editable, but then when running the page I clicked on the column and hid it, and set the current view as the default report.
If anyone stumbles upon this question, I hope it helps.
I'm new to Google script and hoping someone here could answer this.
I have 7 columns and each one has a drop down box so we can select a status "Ready", "Approved", "Waiting" etc.
There will soon be over 500 rows of statuses so ideally I would like to have a function on each column to automatically set the status of the column after it.
Example Cells:
Ready|Waiting|Waiting|Waiting|Waiting|Waiting|Waiting
When the first task is Approved, the cells should look like this:
Approved|Ready|Waiting|Waiting|Waiting|Waiting|Waiting
In the above example, the first cell should be clicked "Approved" by the user from the drop down list. Then the script should read the cell edit, and switch the next cell from "Waiting" to "Ready"
I am looking at the script route as I need to have the drop down cells clickable. If I put a function onto the cell itself, I lose the drop down options.
Any help with this would be really awesome!
Thanks in advance!
You may want to check this YouTube video and this transcribed code can be tweaked to suit your needs:
function setDataValid_(range, sourceRange) {
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange, true).build();
range.setDataValidation(rule);
}
function onEdit() {
var aSheet = SpreadsheetApp.getActiveSheet();
var aCell = aSheet.getActiveCell();
var aColumn = aCell.getColumn();
if (aColumn == 1 && aSheet.getName() == 'Worksheet') {
var range = aSheet.getRange(aCell.getRow(), aColumn + 1);
var sourceRange = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(aCell.getValue());
setDataValid_(range, sourceRange)
}
}
And for additional insights, you may want to also see this thread.