I am currently trying to set up a simple calculation in google sheets that will only add when the value is not equal to the previous value. How can I go about this? All I need is to get the previous value in from the input. It has been a while since I have given my hand at JavaScript so I could be forgetting something simple like that.
I have tried looking into the google API and looking to similar solutions for help. I could just be dumb or missing something simple but does anyone have any idea?
///Call onEdit that takes in the value of e
function onEdit(e)
{
//Get the input value and its previous value
var input = e;
var previous = e; //.prev();? .offset??
//Check if cell is updated
if ( input != previous )
{ return true; }
else
{ return false; }
}
That way
function onEdit(e){
Logger.log(e.oldValue);
}
More details on the event object
You function could be summarised as:
function onEdit(e){
return e.oldValue != e.value;
}
However, I believe that if you just put the same value back in the cell, it's not going to be considered an edit, and thus won't trigger the onEdit() function. So this will always return true when it runs, and not run at all in all other cases.
Related
I added this inside Demo.prototype._handleSortChange to reverse the sort order if the radio is checked...
var order = true;
function reverseOrder() {
if (document.getElementById('order').checked) {
order = true;
} else {
order = false;
}
console.log('reverseOrder: '+order);
}
reverseOrder();
What I can't figure out is to call the sorting function when you check or uncheck the radio input without having to re-select the sort order dropdown.
Demo.prototype.reverseSorting = function () {
// this call resets the sort order to default, rather than just reversing the selected order...
document.getElementById('order').addEventListener('click', this._handleSortChange.bind(this));
};
Codepen https://codepen.io/midaspider/pen/ZEBwBqw
Solved it. I was looking at the wrong section as being the problem, the solution was very simple really.
Demo.prototype._handleSortChange = function (event) {
//var value = event.target.value;
var value = document.querySelector('.sort-options').value;
I realised the value of the select input wasn't being passed if I clicked the checkbox, so I changed var value to explicitly get the value from the select input rather than get the value passed from event. Now it works, I've updated the Codepen for reference in case anyone else needs this.
I am working on a module, which should select the only possible value of a Multi- or Single selection field, if there is only one valid value and a empty one available.
So far its working fine, until I use ACLs to disable selection values.
For example, I got a single selection field with 3 possible values. Then I disable 2 of them (ACL - if there is a special Queue selected) so theres only one value (+ an empty one) left.
My module wont pick the last value at first, but when I change anything else on the same page (second onchange call) it will pick the last possible value.
The first if condition checks if the Field has only one possible value in it. When I log the 'Change' array it always got the disbaled values still in there even when the 'change' that called the whole function was the ACL disabling those values.
Im still kinda new to javascript and havent found a solution yet.
I would realy appreciate any help.
$('.TableLike').on("change", function () {
var Change = [];
$('.Row').each( function() {
$(this).children().next().children().next().children().each( function(index) {
Change[index] = $(this).text()
} )
if ( (!Change[2] || /.*Field needed.*/i.test(Change[2])) && Change[0] === "-") {
SoleOption = Change[1];
$(this).children().next().children().next().children().each(function() {
if ($(this).text() === "-") {
$(this).removeAttr("selected");
}
if ($(this).text() === SoleOption) {
$(this).attr("selected", "selected");
}
} )
$(this).children().next().children().children().children().val(SoleOption)
}
SoleOption = "";
Change = [];
} )
} )
I managed to fix the issue with the setTimeout() Method.
So the DOM updated before the ACL did the changes.
I opened up the setTimeout Method after the onChange method and inserted all the code thats supposed to run after the change into the setTimeout method.
I hope this will be helpfull for others in the future.
I'm trying to come up with an IF statement that will trigger my macro to run based on a specific value in one cell. My Spreadsheet has many tabs. This is for a forecasting template.
Here is what I have come up with but I am running out of ideas..
function Sum_Calcs() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Integrity Check'), true);
spreadsheet.getRange(K20).getValue(getActiveRange(), true);
if(activeRange === "1") {
}
//My Script is then located beneath//
Any help is much appreciated!
You need to
implement an onEdit function to re-evaluate the if statement each time the value in "K20" was changed (please note that it will work automatically only if the value has been changed manually, by a human)
A second function (macro) that will be called within the if statement if your condition is fulfilled
Based on your code snippet above there some things you need to change:
When you use the method getValue() to retrieve the value of a cell - do not specify any parameter within the brackets () of the method. Instead, assign the return value of this method to a variable
If you want to retrieve a cell value (or perform any other operation) in a certain sheet, use getSheetByName() instead of setActiveSheet
To compare within an if statement the actual value against an integer (number) use if(activeRange == 1)
Note that when getting a range in A1 notation you need to use quotes ("")
Sample code based on your situation:
function myForecastMacro(){
// specify here what shall happen if your "if" statement is fulfilled
function onEdit() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName('Integrity Check');
var activeRange=sheet.getRange("K20").getValue();
if(activeRange == 1) {
myForecastMacro();
}
}
I would like to find a way to get the tabulator validation callback to set data to a cell. To explain my use case:
I have a cell I want a user to be able to input data. My custom validator makes sure the inputted data matches in a list of options. Currently the data inputted needs to be case sensitive, As I would like the data to be entered to follow a certain format.
My goal:
Allow a user to input data such as "bob". It fails validation, and the validation callback sees that there is a lowercase match to "Bob", so the cell value should be "Bob".
I think I am 90% of the way there, I have all the logic in place to set the value on callback, but it looks like I might be breaking tabulator in a bad way. The cell looks like its still in edit mode (but lost focus, with a red box around the cell).
My validator code:
var validCheck = function (cell, value, parameters) {
return (AllowedVals.map(function (v) { return v.name;
})).includes(value);
}
My validator callback:
validationFailed:function(cell, value, validators){
if (AllowedVals.map(function (v) { return v.name.toLowerCase(); }).includes(value.toLowerCase())) {
var match = AllowedVals.filter(function (allowedVal) { return allowedVal.name.toLowerCase() == value.toLowerCase() });
cell.setValue(AllowedVals[0].name);
}
},
After the cell gets updated via the validation callback, i cannot edit the cell anymore, the cellEdited method is never called, and there are plenty (48 in total) of errors in the Chrome Dev Console. I have "Maximum call stack size exceeded" and "Uncaught DOMException: Failed to set the 'innerHTML' property on 'Element': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?"
This leads me to believe tabulator is stuck in some sort of validation loop. Can someone help me find the right way to get the behavior I'm looking for?
Mutators are the answer here.
I set my validation to check if its a case insensitive match.
var validCheck = function (cell, value, parameters) {
return (AllowedVals.map(function (v) { return v.name.toLowerCase();
})).includes(value.toLowerCase());
}
Then created a mutator to return the correct case if it finds a case insensitive match.
var Mutate = function(value, data, type, params, component){
if (AllowedVals.map(function (v) { return v.name.toLowerCase(); }).includes(value.toLowerCase())) {
var match = AllowedVals.filter(function (allowedVal) { return allowedVal.name.toLowerCase() == value.toLowerCase() });
return match[0].name;
}
else {
return value;
}
}
In the end it posts the correct data to my server and instantly updates the grid view with the mutated data (Extra Bonus).
EDIT:
Ok so I'm updating this question, to show what I've built as I've still not been able to fix this issue. Here is an image of what I've got. So as you can see,
When the user enters a value, the calculation (they are just percentage and total calculations are done "onkeyup". As you can see because of this they return "NaN". Is there a way for me to stop the field displaying a NaN and then subsequently only showing the total values?
I have thought about this and I could just get all the fields to calculate as soon as something is input into the final field? What do you think. Apologies to all those that had perviously answered my question, I am still trying to figure out the best approach, I'm just not as good with JavaScript as I am with HTML/CSS!!
You should try writing a checkNumber function that takes the entered value as its argument (rather than referring directly to each field inside the function). Something like this:
var checkNumber = function (testval) {
if ( isNaN(testval) ) {
alert('Bad!');
// clean up field? highlight in red? etc.
} else {
// call your calculation function
}
}
Then bind that function to the keyup event of each form field. There are a number of ways to do this. Look into addEventListener(), or the binding features of a framework like jQuery (.delegate() or .keyup(), e.g.).
Note that if you do bind the function to the event, you won't have to explicitly pass in the value argument. You should be able to work with a field's value within the function via this.value. So you'd have something like this:
var checkNumber = function () {
if ( isNaN( this.value ) ) {
alert('Bad!');
// clean up field? highlight in red? etc.
} else {
// call your calculation function
}
}
And then (with a naive binding approach by ID):
document.getElementById('id_of_a_field').addEventListener('keyup', checkNumber, true);
Can't you just initialize the text box with a default value, say 0?
Why don't you use 3 different functions or an argument to identify which of the inputs the user is pressing? If each of the inputs calls checkNumber(1), checkNumber(2) and checkNumber(3) you can only validate the input that the user is using instead of validating all 3 at the same time.
Alternatively you can use input validation and instead of an alert just return false to prevent the user from inputing invalid chars
How about use short-circuit evaluation with jsFiddle example
EDIT for parseFloat:
function checkNumber()
{
var sInput = parseFloat(document.getElementById('sInput').value || 0);
var dInput = parseFloat(document.getElementById('dInput').value || 0);
var pInput = parseFloat(document.getElementById('pInput').value || 0);
if (isNaN(sInput) || isNaN(dInput) || isNaN(pInput)) {
alert("You entered an invalid character. Please press 'Reset' and enter a number.");
}
}
So if pInput is undefined just use 0, but if the input has value then use that value.
SIDE NOTE: white space is actually a number, +' '; // 0