Onedit setvalues does not copy code values, only user input is copied - javascript

https://docs.google.com/spreadsheets/d/1rGns0DGQbjlEpxTbdy1T_-m2oh7eK8tM9xyDzGqahJo/edit?usp=sharing
So I have this code that I thankfully got of the internet but I can't seem to get it to copy the other values in column 'C' from a code I have that fills in empty cells, sheet provided for reference.
function ss1OnEdit(e){
if(e.range.getSheet().getName()!='source_sheet') return;
SpreadsheetApp.openById("1rGns0DGQbjlEpxTbdy1T_-m2oh7eK8tM9xyDzGqahJo").getSheetByName("target_sheet").getRange(e.range.getA1Notation()).setValue(e.value);
}
//You can run this function all you want it will not create more than one trigger. But you must run it once to setup the first trigger.
function createSS1OnEditTrigger() {
var ss=SpreadsheetApp.getActive();
var trgs=ScriptApp.getProjectTriggers();
var found=false;
for(var i=0;i<trgs.length;i++) {
if(trgs[i].getHandlerFunction()=="ss1OnEdit") {
return;
}
}
if(!found) {
ScriptApp.newTrigger("ss1OnEdit").forSpreadsheet(ss.getId()).onEdit().create();
}
}
This code only sets the values that have been entered manually by hand. I would really appreciate if we can have it set cell value from code input.
I have been reading about this for a bit and the getdisplayvalue() but nothing so far worked for me.
Thank you!

I assume that your question is why the user input fires the trigger, but the Range.setValues() doesn't. If that is correct, then it works as written on the simple trigger docs: «onEdit(e) runs when a user changes a value in a spreadsheet». So a user change will fire the trigger, but a script change won't.

Related

How to Use onOpen Trigger Script to Change Google Sheet Behavior?

On the advice of someone below, I am editing this post:
My initial goal is that when my Google sheet is opened, and every time it is opened, I would like the values of several Data Validation dropdown menus, currently located in Cells A10, A15, and A20, to be set to the option of "Select" -- which is a word in the validation range, along with 2 other text values.
I have been informed that this needs to be declared at a global scope -- but I am a complete script novice and, frankly, have no idea as to how to make this work.
Any advice will be greatly appreciated.
function onOpen() {
SpreadsheetApp.getActiveSheet().getRange('A10').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A15').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A20').setValue('Select');
Note for new readers:
The original code on the question was this
//When the sheet is opened, the contents of Cell A2 are cleared and the values in the Data Validation dropdown menus in Cells A10, A15, and A20 are set to the default "Select"
function myFunction() {
function onOpen() {
SpreadsheetApp.getActiveSheet().getRange('A2').clearContent();
SpreadsheetApp.getActiveSheet().getRange('A10').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A15').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A20').setValue('Select');
}
//When the contents of Cell A2 are edited (changed), the values in the Data Validation dropdown menus in Cells A10, A15, and A20 are set to the default "Select"
function onEdit(e) {
var ss = SpreadsheetApp.getActive()
var sheet = SpreadsheetApp.getActiveSheet()
var cell = sheet.getRange('A2')
var cellContent = cell.getValue()
if(cellContent === (edit) {
SpreadsheetApp.getActiveSheet().getRange('A10').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A15').setValue('Select');
SpreadsheetApp.getActiveSheet().getRange('A20').setValue('Select');
}
}
Simple triggers should not be declared as local functions of another function, they should be declared at the global scope.
In other words, don't put onOpen and onEdit inside of myFunction.
A function on the global scope in a Google Apps Script script looks like this:
NOTE: Only one code line is included inside onOpen code block {} for simplicity. It could have any number of code lines that takes no more than 30 seconds to execute.
By the other hand simple triggers has several limitations so maybe instead of simple triggers you should consider to use installable triggers. To learn about Google Apps Script triggers please read https://developers.google.com/apps-script/guides/triggers
Also, you should bear in mind the real-time collaboration features of Google Sheets. If one user has opened the spreadsheet and another user open the same spreadsheet, the onOpen, simple and installable triggers, will be triggered and could change what the first user already edited.
After some testing I was able to make it work. As Ruben said, onOpen, onEdit cannot be inside any other function. These specify already an action so when an action of onOpen or onEdit the script will be running automatically when the spreadsheet is opened or edited.
You can check more information about Apps Script Triggers https://developers.google.com/apps-script/guides/triggers but in this specific case onEdit will run every time any cell is updated unless you specify the cell you want to run the script by using Event Objects for more information check https://developers.google.com/apps-script/guides/triggers/events.
For this specific scenario since you want the script to run when the cell is updated you have to check if that cell is being updated by using e.range.getA1Notation() the getA1Notation() returns the range in A1 notation for more information check https://developers.google.com/apps-script/reference/spreadsheet/range#getA1Notation() there is an example that will make you understand the following script.
function onOpen(e){
var app = SpreadsheetApp.getActiveSpreadsheet();
var sheet = app.getActiveSheet();
sheet.getRange("A2:A2").clearContent();
sheet.getRange("A10:A10").setValue("Select");
sheet.getRange("A15:A15").setValue("Select");
sheet.getRange("A20:A20").setValue("Select");
}
function onEdit(e){
var app = SpreadsheetApp.getActiveSpreadsheet();
var sheet = app.getActiveSheet();
var A2 = sheet.getRange("A2:A2");
console.log(e.range.getA1Notation());
if (e.range.getA1Notation() === "A2"){
console.log("A2 Updated");
sheet.getRange("A10:A10").setValue('Select');
sheet.getRange("A15:A15").setValue('Select');
sheet.getRange("A20:A20").setValue('Select');
}
}
the onOpen function will be running every time the spreadsheet is opened, and the onEdit function will be executed every time the cell "A2" changes its value. Basically you are checking if the range with A1 Notation is equals to "A2" then it will run the code within the if statement, otherwise the function will be executed but will take no action since the cell A2 is still without any change. By doing this I am not sure if there is a limit of this kind of executions but that is something you can investigate further, I don't think it will affect since this should be running on the client side not on a server side.
I hope that helps, greetings.

Debugging script Netsuite suitescript in Chrome exception

So I am trying to add a button to the Sales Order form in netsuite that validates certain fields based on what you entered in previous fields. I am having trouble testing and debugging this in google chrome in netsuite. First, here is my code: I am adding the button that calls this function within the client script record.
function vsoeValidate(){
var calc = nlapiGetFieldValue('custbody_cv_vsoe_calculation');
calc = nlapiGetFieldValue('custbody_cv_renewal_rev_amount') - (nlapiGetFieldValue('custbody_cv_vsoe_cola') * nlapiGetFieldValue(1-'custbody_cv_vsoe_partner_disc')) - (nlapiGetFieldValue('custbody_cv_vsoe_bts_fees') * (1-nlapiGetFieldValue('custbody_cv_vsoe_partner_disc'))) /
(nlapiGetFieldValue('custbody_cv_vsoe_software_amt') * (1- nlapiGetFieldValue('custbody_cv_vsoe_multiyear_disc')));
nlapiSetFieldValue('custbody_cv_vsoe_calculation', calc);
var display = nlapiGetFieldValue('custbody_cv_vsoe_calculation_disp');
var bucket = nlapiGetFieldValue('custbody_cv_vsoe_bucket');
if(bucket === 'X'){
return false;
}
if(calc > (nlapiGetFieldValue('custbody_cv_vsoe_bucket.custrecord_cv_vsoe_maintenance_rate') *1.15) || calc < ('custbody_cv_vsoe_bucket.custrecord_cv_vsoe_maintenance_rate'*0.85)){
display = '<div style="; background-color:red; color:white;font-weight:bold;text-align:center">Out of bounds</div>';
return true;
}
else{
display = '<div style="; background-color:green; color:white;font-weight:bold;text-align:center">In bounds</div>';
return true;
}
}
when I click the button I get the error TypeError undefined is not a function.
I am really not sure where to go from here, is it because the logic inside vsoeValidate is not right or am I using the wrong type of function? Any help would be great thank you!
Update: here is the screenshot of my script record!
Try passing the function name as string i.e.
form.addButton('custpage_validatevsoe', 'Validate VSOE', 'vsoeValidate');
You mentioned that you set vsoeValidate as a validateField function. Do you want this function to run when users click the button or when NetSuite's valdiateField event is fired (upon field change, before the value is stored)?
If you want this to run on NetSuite's validateField event, then the function must return true or false; it cannot return void. Right now in your logic, you have:
if (bucket = 'x') {
return;
}
if (bucket = 'x') is an assignment operation, not an equality check. This assignment operation will return 'x', which is a truthy value, so your code will enter that if-block. You then return void (undefined), so my guess is that NetSuite is trying to do something with the result returned by your function but cannot because it returned undefined.
The validateField function also gets passed a parameter that provides the ID of the field being validated.
You will also want to inject some console logging at various points so you can figure out where your script is failing instead of just trying to guess at reading syntax.
Can you provide us with a screenshot of your Script record setup?
Also since you are using a client side script, you don't need to use the pageInit event for adding a custom button.
There is a 'Buttons' subtab, under the 'Scripts' tab when you create the Script record in NetSuite. This subtab is next to the 'Libraries' subtab.
There are two columns here, 'Label' and 'Function'.
So in your case, you can just put 'Validate VSOE' in the Label field and vsoeValidate in the Function field.
Please note that if you do it this way, the button will only be shown when you are creating or editing a record.

Force a SaveForm in Dynamics CRM 2011 using JavaScript

In CRM 2011, I want to be able to force a save of a form. My requirement is as below.
When the user opens the form, I check if a particular field is empty or not.
If it is empty, I want to force a save, thereby triggering a plugin which will set the field.
My current code is as below. This is in the FormOnLoad function which is associated with LoadForm.
if(checkfield == null){
Namespace.Functions.Contact.FormOnSave();
}
else{
// do nothing.
}
Now, this fails with the following line
Can't execute code from a freed script.
I have no clue as to how to proceed further. As a temporary fix, what I have done is the following
if(checkfield == null){
setTimeout('Namespace.Functions.Contact.FormOnSave()',4000);
}
else{
// do nothing.
}
Any advice on why this is happening and how can I fix it without the timeout would be really helpful?
I have had a look at this question and this, but in my case the form does get loaded or has it actually not yet loaded?
Either way, how can I force a save of a CRM form?
You can save the Form by using:
parent.Xrm.Page.data.entity.save();
But It will only trigger if
(Xrm.Page.data.entity.getIsDirty() == true)
However there is a workaround to set IsDirty property true.
Run the Javascript function on PageLoad. Try to update the value of the field which you are planning to populate through plugin:
For e.g.
function OnPageLoad()
{
var yourField = Xrm.Page.getAttribute("new_yourfield").getValue();
if(yourField == null)
{
parent.Xrm.Page.getAttribute("new_yourfield").setValue("any value");
parent.Xrm.Page.getAttribute("new_yourfield").setSubmitMode("always");
parent.Xrm.Page.data.entity.save();
}
}
You could skip all of this mumble jumbo with loading your form twice with Javascript by creating a plugin registered on the read or the entity. (Or better yet and if possible, on the Create of the entity)
The Plugin would just check for the field, and if it's empty, perform whatever logic you need it to to update the field, then save it, and return the updated field (or possibly just populate the value and don't update the database until the user performs the save)

NetSuite - Fields are not being set in the sales order after I set context to 'scheduled'

Hope you can assist.
I am currently trying to conduct one of the most simplest tasks via a user event script - that is to set a new value in the 'discount rate' field on the sales order. My script works fine when testing it on the client, but when the scheduled script is triggered, the field fails to set/update.
The following code is within a 'beforesubmit' operation. Can you spot what I have done wrong?
function beforeSubmit_discountVAT(type){
if(nlapiGetContext().getExecutionContext() !='scheduled')
return;
var getDiscountVal = nlapiGetFieldValue('discountrate');
var correctDiscount = getDiscountVal / 1.2;
nlapiSetFieldValue('discountrate', correctDiscount);
}
In short - All i want to do is deduct the discount value by 20%. Can you use 'nlapiSetFieldValue' when a user event script is triggered from a scheduled script?
Thanks in advance.
AWB
When editing an existing record, nlapiSetFieldValue cannot be used in a Before Load event on fields that are stored with the record. From the function's JSDocs:
Sets the value of a given body field. This API can be used in user event beforeLoad scripts to initialize field on new records or non-stored fields.
nlapiSetFieldValue can thus only be used reliably in Before Load on new records or non-stored fields.
Realizing this is a month old so you've probably found a solution, I would move your code to the Before Submit event. I tested this using a Scheduled Script:
var customer = nlapiLoadRecord('customer', '31294');
nlapiSubmitRecord(customer);
and User Event on the Customer record, Before Submit event:
if (nlapiGetContext().getExecutionContext() === 'scheduled') {
nlapiSetFieldValue('url', 'http://www.google.com/', false);
}
This works as expected for me in a 2013.1 Sandbox environment.
Using nlapiSubmitField in After Submit as mentioned in the other answer is an unnecessarily long operation that will use extra governance units. Not a huge deal if that's the only thing your script is doing, but if you ever expand the script or add looping, it can add up quickly in terms of performance and governance usage.
Also, it may not be necessary, but you should ensure that getDiscountVal is a Number by doing:
var getDiscountVal = parseInt(nlapiGetFieldValue('discountrate'), 10);
If it comes back as a String then your division operation may give a strange result which may also cause nlapiSetFieldValue to fail or set the field to an odd value.
two suggestions
Make sure that your script is being executed by adding a few nlapiLogExecution statements
Instead of doing it in beforesubmit, change this field in aftersubmit function using nlapiSubmitField
"Can you use 'nlapiSetFieldValue' when a user event script is triggered from a scheduled script?"
Yeah Absolutely yes.Context is also correct its scheduled.
Please make sure that you are submitting the record nlapiSubmitRecord(recordObj) at the end.
If you are not comfortable with nlapiSubmitRecord() you can obviously use nlapiSubmitField()
If still you get stuck up then please paste the complete code so that we could assist you.
Cheers!!!

jQuery validate - adding a rule causes validation to fire

I have code like below to perform some conditional validation on fields in my form. The basic idea being that if something is entered in one field, then all the fields in this 'group' should be required.
jQuery.validator.addMethod('readingRequired', function (val, el) {
//Readings validation - if a reading or a date is entered, then they should all be ntered.
var $module = $(el).closest('tr');
return $module.find('.readingRequired:filled').length == 3;
});
//This allows us to apply the above rule using a CSS class.
jQuery.validator.addClassRules('readingRequired', {
'readingRequired': true
});
//This gets called on change of any of the textboxes within the group, passing in the
//parent tr and whether or not this is required.
function SetReadingValidation(parent) {
var inputs = parent.find('input');
var required = false;
if (parent.find('input:filled').length > 0) {
required = true;
}
if (required) {
inputs.addClass("readingRequired");
}
else {
inputs.removeClass("readingRequired");
}
}
//This is in the document.ready event:
$("input.reading").change(function () {
SetReadingValidation($(this).closest("tr"));
});
This works fine, and I've used pretty much the same code on other pages with success. The slight problem here is that when i enter a value into the first textbox and tab out of it, the validation fires and an error message is displayed. This doesn't happen on other pages with similar code, rather the validation waits until the form is first submitted. Does anybody have any idea why this might be happening?
Hmm. You know how it goes, post a question and then find a solution yourself. Not sure why this works exactly, but changing my binding from:
$("input.reading").change(function () {
SetReadingValidation($(this).closest("tr"));
});
to
$("input.reading").blur(function () {
SetReadingValidation($(this).closest("tr"));
});
Seems to have solved this issue. Would still appreciate being enlightened as to why that might be...

Categories