Use Apps Script to create data validation that uses a named range - validation

Here's the code:
var sheet = spreadsheet.getSheetByName("Timesheet");
sheet.getRange('B27').setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInRange(spreadsheet.getRange('TaskItems'), true)
.build());
The above code successfully creates a data validation drop-down menu in cell B27 that matches the named range "TaskItems". However, the data validation rule that apps script creates uses the actual address of "TaskItems" which is C2:1300, rather than "TaskItems" itself. So if I update the address of named range "TaskItems" to D2:1300, then my data validation rules no longer work because they are still using C2:1300.
I can set the data validation rules manually on each cell to the named range "TaskItems", and everything works great even when "TaskItems" changes. However, I can't get apps script to use the actual named range in the rule rather than the address of the named range when it the rule was created.
I tried switching out the range object with a string like so:
var sheet = spreadsheet.getSheetByName("Timesheet");
sheet.getRange('B27').setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInRange('TaskItems', true)
.build());
but I get an error stating that requireValueInRange does not accept a string.
Does anyone know how to get apps script to use the actual named range in the data validation rule?

I had exactly the same issue and was disappointed to not find an answer here. It's very odd that something you can do manually isn't possible via a script.
But I just figures out a work-around.
Add the validation manually to a cell somewhere which refers to your named range. Then in the script, COPY the validation from that cell to wherever you want it. The copied validation rule uses the name of the named range - just as required.
Here the script I used for testing this.
function setvalidation() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("TEST");
var vrule = sheet.getRange(1,1).getDataValidation();
// Previously, you would have set up the validation in cell A1
sheet.getRange(1,2).setDataValidation(vrule); // Copy the validation rule to cell A2
}

Related

JavaScript: how to trigger update form after setting input

I am writing a simple App Inventor program to populate a Covid-19 school health check page. I am stuck on selecting a school. Normally you type in a school name, the page finds string matches and you select from the list of string matched school. I am able to simply set the field manually but the rest of the form doesn't update. I know I must trigger an update but I cannot make head or tails of how this page works.
image of school selection
typing in part of school name
From the Chrome console I can do the following:
x = document.getElementsByClassName("k-textbox")
x[1].value = "Horace"
From the picture you can see the text was updated to "Horace" but the results have not updated. What should I do to force an update so the results list shows proper matches? Also, how do I query the matching results so I can confirm that my input was explicit enough to return a single match? FYI, this form entry page will be hidden to the user.
You can get the kendoDropDownList, call the read method from it's dataSource, and pass the locationName value of what you want. This won't set the text in the textbox, but it will filter your list down like you want.
To test, click on the input, open your console, and run the following:
$('#Location').data('kendoDropDownList').dataSource.read({ locationName: 'horace' })

app scripts data validation from another workbook

I'm trying to validate cells based on a list from a different sheet in a separate workbook. I tested it by copying the desired sheet into the current workbook, to build the code. I changed all the references to reflect the actual source I wanted and everything seemed fine. when I deleted the copy I then had issues as it seems the data validation was still using the copy even though all the references were changed to the original source.
var DbSheet = SpreadsheetApp.openByUrl(ingredientDbBookUrl).getSheetByName(ingredientDbBookName);
function nameValidation(){
var cell = sheet.getRange(3,nameColumn,recipe.getLastRow(),1);
var list = DbSheet.getRange(3,2,ingredientDbSheet.getLastRow());
var helpText = 'helptxt';
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(list)
.setAllowInvalid(false)
.setHelpText(helpText)
.build();
cell.setDataValidation(rule);
is it possible to validate cells from a list in a separate workbook? does the fact that I'm using a bounded script matter?
I did it with this:
function validatefromanothersheet() {
const ss=SpreadsheetApp.openById("Another ssid");
const sh=ss.getSheetByName('Sheet1');
const list=sh.getRange(1,1,sh.getLastRow(),1).getValues().flat();
let rule=SpreadsheetApp.newDataValidation()
.requireValueInList(list)
.setAllowInvalid(false)
.build();
SpreadsheetApp.getActiveSheet().getRange(1,1,10,1).setDataValidation(rule);
}
Is it possible to validate cells from a list in a separate workbook?
Yes
Does the fact that I'm using a bounded script matter?
No
Why did the validation have errors?
This is likely because once you have "set" the validation on a cell, it doesn't matter what the code is that was used to generate it.
It is like building something from a plan, and then expecting the building to change because you have changed the plan.
You would need to first clear the rule and then build the rule and apply it again with the new source.
Just probably best to not use requireValueInRange(range) as the ranges may get crossed over. But if you are converting it to values as your code demonstrates said above, then it should be no issue.
Ref
DataValidationBuilder

DOORS DXL issue looping through a filtered dataset

I have a script in which I filter the data in a module by a certain attribute value. When I then loop through these objects, for now, I am displaying the absolute number of the objects in an infoBox. However, the script is displaying absolute numbers of objects that are not in the dataset. Upon further investigation, I found that the extra absolute numbers were for each table within the entire module. I can't figure out why the script would include these tables when they are not in the filtered module data. I have even tried manually filtering the module on this attribute value then use the "Tools -> Edit DXL" to loop through the resulting items and it still displays the numbers for the tables that are not included. Why would it do this?
Here's my code:
bm2 = moduleVar
Filter fltr = contains(attribute "RCR_numbers", sRCRNum, false);
filtering on;
set(bm2, fltr);
for oObj in document(bm2) do {
absNum = oObj."Absolute Number";
infoBox("Object #" absNum ".");
}
I have also tried removing the document cast so it says "for oObj in bm2 do" instead, but this doesn't change the output. Why is the code giving me objects that are not in the filter? Any help would be greatly appreciated since this is a high priority issue for my project and I'm out of ideas myself.
Chris
In the DOORS 9.6.1 DXL Reference Manual you can see that:
for object in document
Assigns the variable o to be each successive
object in module. It is equivalent to the for object in module loop,
except that it includes table header objects, but not the row header
objects nor cells.
So, you must either use for object in module or, within your existing loop, test the hidden attribute TableType - this will be set to TableNone for anything that is not part of a table, table headers included.

Optional URL parameters with url routing in webforms

Playing with the new(ish) url rewriting functionality for web forms, but I'm running into trouble trying to declare parameters as optional.
Here's the scenario. I've got a search function which accepts two parameters, sku and name. Ideally I'd like the URL for this search function to be /products/search/skuSearchString/nameSearchString. I also have various management pages that need to map to things like /products/management/ or /products/summary/. In other words, the last two parameters in the URL need to be optional - there might be one search string, or two, or none.
This is how I've declared my virtual URL:
Friend Const _VIRTUALURL As String = "products/{action}/{sku}/{*product}"
And added the following defaults:
Me.Defaults = New Web.Routing.RouteValueDictionary(New With {.sku = "/"})
Me.Defaults = New Web.Routing.RouteValueDictionary(New With {.product = "/"})
I have two problems with this setup. The most pressing is that the url seems to expect an sku parameter. So, /products/summary/ cannot be found but /products/summary/anyTextAtAll/ maps to the correct page. You get the same result whether the defaults are set to "/" or "". How do I ensure both sku and product parameters are optional?
The second is more a matter of interest. Ideally, I'd like the url to be able to tell whether or not it's got a product search string or a url search string. The obvious way to do this is to make one or the other default to a value I can just pick up and ignore, but is there a neater way of handling it?
I'm not sure I entirely understood the question, but I have some comments about what you've shown so far:
The manner in which you're setting defaults seems incorrect. You're first setting a default value dictionary with a value for "sku". You're then replacing the default value dictionary with a value for "product".
A default value of "/" is unlikely to be what you want. In this case it sounds like you want a default value of just "" (empty string).
Try something like:
Me.Defaults = New Web.Routing.RouteValueDictionary(New With {
.sku = "",
.product = "" })
My VB skills are rather weak, so the syntax I showed might not be exactly right.
I think that if you change both of these then you should be good to go.

How do I swap items in a VB6 collection?

If I have a collection of forms (myForms) and I want to switch the position of two forms in the collection (say items 3 and 4 for example), I would expect that the following code would work:
Dim temp as Form
Set temp = myForms(3)
Set myForms(3) = myForms(4)
Set myForms(4) = temp
But that doesn't work. It fails at the third line with the error "Controls property is read only." If I change the line to:
myForms(3) = myForms(4)
I get a type mismatch error instead.
If myForms is a standard collection:
Dim myForms as New Collection
(which is actually different from the controls collection) and you've added the forms using:
myForms.Add frmOne, myForms.Add frmTwo
etc then (yes) you do need to use the Add and Remove methods because of the way the collection references the added objects.
Otherwise the interpretation is that you actually want to replace one form with another and this is not allowed. You can't say:
Set frmOne = frmTwo
unless these are actually variables of type Form.
Why do you need to switch the order? Are you referencing the item numbers somewhere? Would using a Dictionary to collect the forms and reference them by a key be useful?
PS. The type mismatch is simply because both items are objects and need to be 'Set'.
You can't actually swap around items in the controls collection in VB6. You need to use the Add and Remove functions associated with each. Check out this article:
http://support.microsoft.com/kb/190670
Hope this helps!

Resources