Using a custom function in Data Validation - javascript

I am trying to use a custom function developed in Google Script to validate a value in the spreadsheet.
However I get a response: There is a problem "Enter a value that satisfies the formula: =validateContent()"
The function itself has not been called at all.
Am I pushing Google Spreadsheet validation too far here with custom function?
I was expecting my function to return true or false, is that how it is suppose to work?
function validateContent() {
var val = SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue();
if (val == value) return true;
return false;
}

First, to validate the current cell input it is useful to follow the pattern suggested by google:
=ISODD(C8)
In your case:
=validateContent(C8)
The validation generator is smart enough to translate the cell reference correctly to all other cells! I.e if this validation is applied to C8:C100 the validation of cell C42 will read =ISODD(C42).
Still, I have found that custom functions seem not to work in validation! See the following example:
In this screenshot the cell G2 uses a custom validation function (=ssvDataVerify(G2)), which evaluates to TRUE but is shown as invalid (red corner)! As a proof, the data value of cell I2 is =ssvDataVerify(G2). Now the validation if I2 is =I2, which now is shown as correctly validated!
I conclude that currently custom functions are not implemented to work with validation.

Currently, functions cannot be used in validations, but there is a workaround:
Use your custom function in some cell, let's say B2: =validateContent(A2).
Add a validation to cell A2 with the criteria Custom Formula is -> =B2.

I also believe that custom functions don't work for data validation.
I created a function to check a string value , against a list of RegExp and it didn't worked:
function vaidate(){
var range = SpreadsheetApp.getActive().getRange('A1');
var validation = SpreadsheetApp.newDataValidation().requireFormulaSatisfied('=checkValid(A1)').build();
range.setDataValidation(validation);
}
function checkValid(text){
var regexs = [/\|{2,}/g,/\.{2,}/g,];
var valid = true;
for(var i=0;i<regexs.length;i++){
if(testString(text,regexs[i])){
valid = false;
break;
}
}
return valid;
}
function testString(str, regex){
try{
var localRegex = regex;
return localRegex.test(str);
}catch(e) {
return false;
}
}

Here you go :)
The idea is to build the validation rule once the cell is edited
function onEdit(e){
const isValid = validateValue(e.value);
const rule = SpreadsheetApp
.newDataValidation("Yep")
// You can use any function but i believe you only need to use "EQ" with boolean
.requireFormulaSatisfied('=EQ("'+isValid+'","TRUE")')
// Your help message
.setHelpText('Please Enter "123" :P')
// Building the rule
.build();
e.range.setDataValidation(rule);
}
function validateValue(value){
// do what ever you want ;)
return value === "123";
}

Related

Javascript function parameters in Acrobat

Hopefully you all don't get pissed at me for such a seemingly simple question..
Basically, I have a PDF form that I'm scripting with javascript.
I have a bunch of check boxes that I would like to set required and/or not required based on other inputs and I'm trying to repeat code as little as possible, especially since there's a ton of inputs.
Right now, the best way I can accomplish what I'm attempting is by setting a function for each instance of inputs as follows:
function setWalkwayNotRequired() {
this.getField("sidewalkAsphalt").required = false;
this.getField("sidewalkConcrete").required = false;
this.getField("sidewalkPavers").required = false;
this.getField("sidewalkCondition").required = false;
}
I would then call this function based on the input of a certain checkbox:
if (this.getField("sidewalkNone").value == "Yes") {
setSidewalkNotRequired();
}
Then all of the above-mentioned fields would be set to not required.
I feel like there should be a way to create a single "setRequired" or "setNotRequired" function to take a parameter of the field in question.
In my mind that would look something like this:
function setRequired(a, b, c, d) {
this.getField(a).required = true;
this.getField(b).required = true;
this.getField(c).required = true;
this.getField(d).required = true;
}
I would then call on that function for all instances, for example, walkways (like that above) or driveways, etc. like so:
if (this.getField("sidewalkNone").value == "Off") {
setRequired('"sidewalkAsphalt"', '"sidewalkConcrete"', '"sidewalkPavers"', '"sidewalkCondition"');
}
Again, in my mind what would then be output based on the above code once the function is called is something like:
if (this.getField("sidewalkNone").value == "Off") {
this.getField("sidewalkAsphalt").required = true;
this.getField("sidewalkConcrete").required = true;
this.getField("sidewalkPavers").required = true;
this.getField("sidewalkCondition").required = true;
}
Doing it the way I did in the first code block would require me to create separate functions for each set of checkboxes, creating a lot of code in an already huge file. The second way would allow me to use 1 function over and over throwing the field names as parameters depending on where I'm at in the PDF.
I'm also not very clear on if it's even legal to declare the parameters as I did with the '"..."' quotes; I did that because I need the double quotes inside the this.getField().
Again, I'm sorry if this is novice, I've just been trying to play with the code for a while now and can't get it to work.
Any input would be amazing.
You could just pass in an Array of field names:
function setRequired( fieldNames, isRequired = true ) {
for( var i = 0; i < fieldNames.length; i++ ) {
var fieldName = fieldNames[i];
this.getField( fieldName ).required = isRequired;
}
}
Usage:
if( this.getField("sidewalkNone").value == "Off" ) {
setRequired( [ "sidewalkAsphalt", "sidewalkConcrete", "sidewalkPavers", "sidewalkCondition" ] );
}
If you use hierarchical naming with dot notation, you can set properties on the parent to affect all children. For example, if you name the fields "sidewalk.Asphalt", "sidewalk.Concrete", and "sidewalk.Pavers"...
this.getField("sidewalk").required = true;
... will set all the children to be required.

Xpages how to check in javascript if a date is blank?

This is really weird. I am doing validation in a js library. I check if fields are blank or null and throw an error if they are.
I have a date field that I want to check. If I do not put in a default value, the code works fine. It says the date is blank and then when I put in a value it lets it pass. But if I put in a default of #Now or #Today, it will not pick up the error if the user happened to erase the date. I know it is not really necessary - I could put a required validator on, but it is driving me crazy that I cannot figure this out.
//This SSJS script library consolidates all the validation in one place
//The postValidationError() function flags a control as invalid and provides an error message
//so that the XPages ErrorMessage control is used to display the error on the page.
var validateForm = function(){
var valid = true;
var control;
var val;
// *** REPEAT THE FOLLOWING BLOCK OF CODE FOR EACH CONTROL FOR BASIC "REQUIRED" VALIDATION
// For each field, change the Control Name in getComponent() and the error message text in postValidationError()
// Optionally, modify the IF conditions with more complex JavaScript for value ranges, regular expressions, data lookups, etc.
//Validate Location
control = getComponent("loc");
val = control.getValue();
if (isEmpty(val)) {
valid = false;
postValidationError(control,"Please enter a Loc");
}
//Validate Work Category
control = getComponent("workCategory");
val = control.getValue();
if (isEmpty(val)) {
valid = false;
postValidationError(control,"Please enter a Work Category");
}
//Validate Work Sub Category
control = getComponent("workSubCategory");
val = control.getValue();
if (isEmpty(val)) {
valid = false;
postValidationError(control,"Please enter a Sub Work Category");
}
//Validate Date
control = getComponent("date");
val = control.getValue();
if (isEmpty(val)) {
valid = false;
postValidationError(control,"Please enter a date");
}
//Validate Time Spent
control = getComponent("timeSpent");
val = control.getValue();
if (isEmpty(val)) {
valid = false;
postValidationError(control,"Please enter Time Spent");
}
// *** ---------------------------------------------------------------- ***
return valid;
}
function postValidationError(control, msg) {
if ((typeof msg) != "string")
return;
var msgObj = new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, msg, msg);
facesContext.addMessage(control.getClientId(facesContext), msgObj);
control.setValid(false);
}
function isEmpty(o){
return (o == null || o == "") ? true: false;
//return (o == null || #Trim($A(o)[0]) == "" ) ? true : false;
}
function $A( object ){
try {
if( typeof object === 'undefined' || object === null ){ return []; }
if( typeof object === 'string' ){ return [ object ]; }
if( typeof object.toArray !== 'undefined' ){return object.toArray();}
if( object.constructor === Array ){ return object; }
return [ object ];
} catch( e ) { }
}
Bryan, the recommended way in XPages for validation is to use a validator, You write much less code, you can selectively control when to validate fields, you can separate different checks from each other.
Check my thoughts about validation. In a nutshell:
Validation in code (a button, the submit event etc.) is a typical way validation is done. Being the prevalent way doesn't make it right . You need to roll your own notification mechanism (like updating a label) and tend to tie your validation into the UI. Also when you remove a field the validation routine is likely to break. Last not least: you have a hard time documenting what gets validated and why. (You see where I'm going with that)
Validators are defined together with a field and open a series of possibilities. XPages offers 9 different validators.
You can write JavaScript, regular expressions, check for data types or roll your very own. All you can do in a button/event code you can do in a validator. Since the validators themselves don't interact with the UI the designer can decide how to surface the messages without changes to the validation code. When you remove a field all its validation code goes with it, so maintenance gets much easier. Last not least: you can run an XSLT report against your XPages source and render a report that shows a field with all the defined validators, which makes documentation easier.
Form Validation are the #Formulas defined in your classic Notes form. They only fire when you have specified "Run form validation" as "On Save" or "Both". Typically you would use those when upgrading existing applications.
Extracted from another blog entry

Trigger a function in Javascript, if the word is in dictionary

I want to perform an action after the user typed in a textbox. I will be using onkeyup in the textbox.
i want a condition, that will allow the user to perform a task, only if the typed word is a dictionary word or a proper word.
Eg :
if the user types hello, then alert the word Hello.
if the user types helr, then alert that this is not a dictionary word.
HTML :
<input type="text" onkeyup="chk();"/>
<span id="indicate"></span>
Javascript :
function chk() {
if(spellcheck()) {
document.getElementById("indicate").innerHTML = "Correct Word";
}
else {
document.getElementById("indicate").innerHTML = "Wrong Word";
}
}
Please Help me defining the function spellcheck() which will return 1 or 0.
I want this to be performed in client side itself, using javascript.
Thanks in advance.
Returning 1 and 0 is not good for JavaScript. Better return true and false from the function. Now, you can define your dictionary in form of array and then check if the input word is present in dictionary or not.
var dictionary = ['Hello', 'Welcome', 'Bye'];
function spellcheck(value) {
var returnVal = false;
var length = dictionary.length;
for (var inc = length - 1; inc >= 0; inc--) {
if(value.toUpperCase() === dictionary[inc].toUpperCase()) {
returnVal = true;
break;
}
}
return returnVal;
}
You can see full example here http://jsbin.com/IgaPEBi/3/edit?html,js,output
You can use the Typo.js dictionary
To use Typo, simply include the typo.js file in your extension's background page, and then initialize the dictionary like so:
var dictionary = new Typo("en_US");
var is_spelled_correctly = dictionary.check("hello");
or http://www.javascriptspellcheck.com/ for an auto suggestions box.
Make a call to an API dictionary service, there are some opensource ones:
wiktionary
glosbe.com
dictionary-api
When the user finishes typing you can use a function to make an async call (AJAX with JS or Jquery) to the APIs endopoint; if the object in the response is not void or null or just states there are no words in the dictionary, your function can return 0, else 1.
Usually the endpoint address is something like URL/action/*word* , where action is what you want to know and word is the actual word you look for.

What does unescape() function returns?

I have to use unescape() function in an if-else statement. In my website I have two pages, one with a form that the user fills and the second page have to get the information from the filled form by unescape function. I need the if-else statement because in the form I put two radio buttons that each one adds different text areas with different ids' and names so I want to check in the second page what text fields are are filled. (all the fields created by clicking on a radio button which starts a javascript function so in the next page I must check if the field was created and not just to check if it is an unfilled text field).
It is a little bit hard for me to explain so just check the code. In the code you will see params["placeName"] and so on, so placeName for example like all the others is a text field name from the previous page.
So the question is - what does unescape function returns if the component name I insert as a paramater does exist in the previous page?
<script type="text/javascript">
function getParams() {
var idx = document.URL.indexOf('?');
var params = new Array();
if (idx != -1) {
var pairs = document.URL.substring(idx + 1, document.URL.length).split('&');
for (var i = 0; i < pairs.length; i++) {
nameVal = pairs[i].split('=');
params[nameVal[0]] = nameVal[1];
}
}
return params;
}
params = getParams();
//from here it is what I want to do (I don't know if this condition in the if statement is correct, this is what I ask)
// if (unescape(params["placeName"]) == false) {
// }
// else {
var place = unescape(params["placeName"]);
var country = unescape(params["country"]);
var city = unescape(params["city"]);
var address = unescape(params["address"]);
var type = unescape(params["type"]);
var rate = unescape(params["rate"]);
// }
</script>
It can also work if I could check what radio button is checked
You are asking what will unescape(params["something"]) return if params["something"] is not present. The answer is undefined. So you need to check equivalence to "undefined". Meaning: if (unescape(params["placeName"]) == "undefined") (in this case params["placeName"] is not present (was not created).
The undecode function returns -as it's name indicated- a decoded string. If you enter a value that's not defined it will probably cause an error because of the indefinition. If what you want is to check whether the element was or not created or not you could use
if (params.placeName !== undefined) {
// It was created
}
instead.
Aditionally, if you want to check which radio button was checked use
if (document.getElementById('foo').checked) {
// Radio button with id 'foo' was checked
} else if (document.getElementById('bar').checked) {
// Radio button with id 'bar' was checked
} else if
...

JQuery compare arrays for any match

I'm having a pretty simple issue I think but I cannot get it solved.
On form submit I want to compare the values of two hidden input types and if any match is found return an alert to the user and prevent submit. Pretty much the hidden input type values will be 1-3, could be 1, 12, 123, 13 etc. So if 1 and 123, throw an alert.
So I've tried something like this, but I'm obviously confused about what I'm doing hehe.
var new_products = $('#new_products');
var array_new_products = jQuery.makeArray(new_products);
var existing_products = $('#existing_products');
var array_existing_products = jQuery.makeArray(existing_products);
$("#my_form").submit(function(e) {
if (jQuery.inArray(existing_products, new_products) >= 0) {
e.preventDefault();
alert ("This Promotion matches one or more products already associated to this Group. If you continue the existing Promotion will be cancelled and replaced with the currently selected Promotion!");
}
return true;
});
I'm open to doing this by comparing strings and returning matches or anything really. I'm just pretty new to Jquery. Thanks in advance.
$.each($('#new_products').val().split(''), function(i, char) {
var existing = $('#existing_products').val();
if (existing.indexOf(char) != -1)
alert('mathces found');
});
checks if any of the characters in the returned value from #new_product exists in the value returned from #existing_products ?

Categories