Make TODAY formula stop when checkbox is clicked - date

I'm setting up a Google Sheet with a few columns to be filled for a certain request. So, I included a checkbox to be clicked at the end as a confirmation the request is done. My idea is to have an automated column called 'Request Date' automatically filled with the current date as soon as the Confirmation checkbox is clicked. However, can't use TODAY() formula once it's going to change the date every day. Any solution for this?

unfortunately no. you can't stop TODAY on demand by any means without a script. but you could have a script which would print out the date if certain checkboxes were checked.
function onEdit(e) {
var aCell = e.source.getActiveCell(), col = aCell.getColumn();
if(col == 5) { //number of column where you have a checkbox
var adjacentCell = aCell.offset(0,1);
var newDate = Utilities.formatDate(new Date(),
"GMT+1", "dd/MM/yyyy");
adjacentCell.setValue(newDate);
}}
this will print date in column F if a checkbox in column E is checked
or perhaps like this:
function onEdit(e) {
var activeSheet = e.source.getActiveSheet();
if (activeSheet.getName() == "Sheet1") { // SHEET NAME
var aCell = e.source.getActiveCell(), col = aCell.getColumn();
if (col == 12) { // COLUMN WITH CHECKBOXES
var dateCell = aCell.offset(0,1); // OFFSET ROWS, COLUMNS
if (aCell.getValue() === true) { // VALUE OF CHECKED CHECKBOX
var newDate = new Date();
dateCell.setValue(newDate);
} else {
dateCell.setValue("");
}}}}

Related

Getting the cell given the cell value in google sheets using app script

I'm trying to write a script that tracks payment dates in google sheets (shows a different colour (either FontColor or Background) three days before payment, another colour on the day of payment and a totally different colour after the payment date.I'd appreciate if there's anyone with know how on how to use those values to get the cell name and use it to change the FontColor or alternatively if there's a better solution
Here is my google sheet
[![enter image description here][1]][1]
This is the code I've written to get the dates into a list
function myFunction() {
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let lastRow = spreadsheet.getLastRow();
let lastCol = spreadsheet.getLastColumn();
var dataRange = spreadsheet.getActiveSheet().getRange(2, 11, lastRow, lastCol)
dataRange.setFontColor("green")
var data = dataRange.getDisplayValues();
let dates=[];
for (let i=0; i < dates.length; i++ ) {
// console.log(dates[i])
if (dates[i] === new Date().toLocaleDateString()) {
dataRange.setBackground('pink')
} else if (dates[i]) {
// do sth
} else {
// maintain the current state
}
}
}
Does it need to be with scripts?? With conditional formatting that would be MUCH faster, easier and uploads constantly.
You can apply it to the entire sheet or to a specific range. Use this custom formula (change A1 with the top left formula of your range)
=if(A1="",FALSE,(A1 - Today()) < 0)
Get sure to set these conditions in the correct order (in these case it would be preferrable to be the past dates, the actual date and the close future dates). Like this:
Here you have a link to play with:
https://docs.google.com/spreadsheets/d/1zhEFRQwOyAYQwXfv5lYTjI7B-6fIfz1rgdCt3MGvzmI/edit?usp=sharing
Payment Tracker
function paymentTracker() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const rg = sh.getRange(2, 11, sh.getLastRow() - 1, sh.getLastColumn() - 10);
rg.setFontColor("black")
const vs = rg.getDisplayValues();
const d = new Date();
//Logger.log('y: %s,m: %s,d: %s', d.getFullYear(), d.getMonth(), d.getDate());
const dt = new Date(d.getFullYear(), d.getMonth(), d.getDate());
const dtv = dt.valueOf();
const dt3 = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 3);
const dt3v = dt3.valueOf();
vs.forEach((r, i) => {
let ds = r.map(ds => {
let t = ds.split('/');
//Logger.log(JSON.stringify(t))
let v = new Date(Number(t[2]), Number(t[1]) - 1, Number(t[0])).valueOf();
let diff3 = dt3v - v;
if (dt3v == v) {
return "purple";
} else if (dtv == v) {
return "green";
} else {
return "pink";
}
});
sh.getRange(i + 2, 11, 1, ds.length).setBackgrounds([ds]);
})
}

Reverse sort data in Google Sheet

Google Forms linked to Google Sheets record submissions oldest to newest. We must scroll to the bottom of the sheet for the newest submission. I'd like to reverse that behavior so the newest submissions are at the top and oldest at the bottom. What is the best way to do this?
Try (put a trigger on onFormSubmit)
function onFormSubmit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var column = e.values.length + 1;
var range = sheet.getRange(2, 1, row-1, column);
range.sort({column: 1, ascending: false});
}

sap.m.table multi checkbox make it READ ONLY - On Condition + SAP UI5

This is my first post to Stack, appreciate the work you guys do, amazing.
I have a sap.m.table sap ui5 and i have 4 records
out of 4, 2 are selected by default, i want to disable the preselected once based on condition.
I have tried below code but its not working, any input please?
View
/results' }" **mode="MultiSelect"**
Controller logic
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
var header = tbl.$().find('thead');
var selectAllCb = header.find('.sapMCb');
selectAllCb.remove();
tbl.getItems().forEach(function(r) {
var obj = r.getBindingContext("impactModel").getObject();
var oStatus = obj.COMPLETED;
var cb = r.$().find('.sapMCb');
var oCb = sap.ui.getCore().byId(cb.attr('id'));
if (oStatus === "X") {
oCb.setSelected(true);
oCb.setEnabled(false);
} else {
oCb.setEnabled(false);
}
});
Multiselect Mode Table - Make selected check box read only
Last time I tried this I found it easiest to use the updateFinished event on the table, and then use an internal property of the column list item, like so:
onTableUpdateFinished: function (oEvent) {
oEvent.getSource().getItems().forEach(function (item) {
var data = item.getBindingContext().getObject();
item._oMultiSelectControl.setEnabled(!data.IsEnabled); //whatever your check is
});
}
You'll have to find a way to keep them disabled though when using the Select All checkbox at the top of the table. I ended up extending sap.m.Table to accomplish that, there might be easier ways...
My extension is like this
sap.ui.define([
"sap/m/Table"
], function(Control) {
return Control.extend("myapp.controls.MyTable", {
updateSelectAllCheckbox: function(oEvent) {
if (this._selectAllCheckBox && this.getMode() === "MultiSelect") {
var aItems = this.getItems();
var iSelectedItemCount = this.getSelectedItems().length;
var iSelectableItemCount = aItems.filter(function(oItem) {
//standard table does not check if the item is enabled
return oItem.getSelected() || oItem._oMultiSelectControl.getEnabled();
}).length;
// set state of the checkbox by comparing item length and selected item length
this._selectAllCheckBox.setSelected(aItems.length > 0 && iSelectedItemCount === iSelectableItemCount);
}
}
});
});
And just the standard renderer
sap.ui.define([
"sap/m/TableRenderer"
], function(Control) {
return Control.extend("myapp.controls.MyTableRenderer", {
});
});
I suppose I could have extended the ColumnListItem but that was more effort than I wanted to put into the table extension
I have managed to find the solution, please find sample code to achieve.
//--->disable the selected department checkboxes
var tbl = that.getView().byId("idImpactTable");
var header = tbl.$().find("thead");
var selectAllCb = header.find(".sapMCb");
selectAllCb.remove();
var aItems = that.byId("idImpactTable").getItems();
//---> Check individual item property value and select the item
aItems.forEach(function(oItem) {
debugger;
//---> If using OData Model items Binding, get the item object
var mObject = oItem.getBindingContext().getObject();
var sPath = oItem.getBindingContextPath();
var completed = oItem.oBindingContexts.impactModel.getProperty("COMPLETED");
//--->get the id of Multi Checkbox
var cb = oItem.$().find(".sapMCb");
var oCb = sap.ui.getCore().byId(cb.attr("id"));
if (completed === "X") {
oCb.setEditable(false);
oItem.setSelected(true);
oItem.getCells()[4].setEnabled(false);
} else {
oItem.setSelected(false);
}
});
Thank you,
Jacob.Kata
//--->disable the selected department checkboxes
var tbl = that.getView().byId('idImpactTable');
tbl.getItems().forEach(function(r) {
// this makes the trick --->
var oMultiSelCtrl = r.getMultiSelectControl();
oMultiSelCtrl.setDisplayOnly( true );
});

How to add row selection checkbox for ag-grid

Is there a way to have row selection checkbox for each row without configuring a special column for it? I mean to add propertie for my gridOptions and to see checkbox near each row, then to get all selected rows?
All the documentation I read is showing how to do it by adding it to specific column.
Thanks,
You can still have row selection without having a checkbox column - you can either simply have selection based on row selection, or have a column render with a checkbox in it (with a custom cell renderer).
Take a look at the Selection Documentation for more information about row selection, and at the Cell Rendering Documentation about cell rendering
I know it is too late to answer on this post. But It may help someone who look for solution still. It works with checkbox selection on each row (click anywhere on the row to select checkbox), shift/control and toggle selection. Here I have given only necessary code.
vm.gridOptions = {
appSpecific : {},
onRowClicked : onRowClicked,
onGridReady : function() {
let api = vm.gridApi = vm.gridOptions.api;
}
};
function toggleSelect(row) {
row.node.setSelected(!row.node.isSelected(), false);
}
function onRowClicked(row) {
var appSpecific = vm.gridOptions.appSpecific;
var lastSelectedRow = appSpecific.lastSelectedRow;
var shiftKey = row.event.shiftKey;
// if not modifier keys are clicked toggle row
if (!shiftKey) {
toggleSelect(row);
} else if (lastSelectedRow !== undefined) {
if (shiftKey) {
var startIndex, endIndex;
// Get our start and end indexes correct
if (row.rowIndex < lastSelectedRow.rowIndex) {
startIndex = row.rowIndex;
endIndex = lastSelectedRow.rowIndex;
}
else {
startIndex = lastSelectedRow.rowIndex;
endIndex = row.rowIndex;
}
// Select all the rows between the previously selected row and the
// newly clicked row
for (var i = startIndex; i <= endIndex; i++) {
vm.gridApi.selectIndex(i, true, true);
}
}
}
// Store the recently clicked row for future use
appSpecific.lastSelectedRow = row;
getSelection(); // Implement functionality to get selected rows
}

Bootstrap datepicker with knockout.js databind

This question is similar to knockoutjs databind with jquery-ui datepicker, but instead of the jQueryUI datepicker, I would like to use one of the Bootstrap datepickers.
The API for the Bootstrap datepicker is different from jquery-ui, and I am having some trouble wrapping my head around making it work with knockout.js. I have created a jsFiddle to try it out.
It seems like the Bootstrap datepicker could be much simpler to use because it does not independently store the date. However, I would like to know how whether the jsFiddle is the appropriate way to use the Bootstrap datepicker widget with knockout.js i.e.
ko.bindingHandlers.datepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).datepicker("destroy");
});
},
update: function(element, valueAccessor) {
}
};
Here is a sample of how you could accomplish this with the datepicker that you are using:
ko.bindingHandlers.datepicker = {
init: function(element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
//when a user changes the date, update the view model
ko.utils.registerEventHandler(element, "changeDate", function(event) {
var value = valueAccessor();
if (ko.isObservable(value)) {
value(event.date);
}
});
},
update: function(element, valueAccessor) {
var widget = $(element).data("datepicker");
//when the view model is updated, update the widget
if (widget) {
widget.date = ko.utils.unwrapObservable(valueAccessor());
if (widget.date) {
widget.setValue();
}
}
}
};
It did not look like there was any destroy functionality, so I removed that piece. This handles the widgets changeDate event to update the view model, when a user changes the date. The update function handles when the view model is changed to update the widget.
If you want to bind the value to a non-observable, then it would take a little more code. Let me know if that is something that you need to support.
http://jsfiddle.net/rniemeyer/KLpq7/
my current version is a mix between the already shown solutions:
ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
var unwrap = ko.utils.unwrapObservable;
var dataSource = valueAccessor();
var binding = allBindingsAccessor();
//initialize datepicker with some optional options
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
$(element).datepicker('update', dataSource());
//when a user changes the date, update the view model
ko.utils.registerEventHandler(element, "changeDate", function (event) {
var value = valueAccessor();
if (ko.isObservable(value)) {
value(event.date);
}
});
},
update: function (element, valueAccessor) {
var widget = $(element).data("datepicker");
var value = ko.utils.unwrapObservable(valueAccessor());
//when the view model is updated, update the widget
if (widget) {
widget.date = value;
if (widget.date) {
widget.setValue();
$(element).datepicker('update', value)
}
}
}};
The accepted answer didn't work for me with the current version of the date picker. The input wasn't being initialized with the value of the observable. I made an updated binding, to which I added this:
$(element).datepicker('update', dataSource());
That seems to do the trick.
Here's an updated fiddle that uses the latest available date picker, Bootstrap, jQuery, and Knockout: http://jsfiddle.net/krainey/nxhqerxg/
Update:
I experienced some difficulty with the date picker not playing nicely with the observable when a user would edit the value in the text field manually. The tool would immediately parse the date, and plug the result into the input field.
If the user tried to edit 10/07/2014, for example, and used the backspace or delete to remove a number (10/0/2014), the resulting value would be parsed immediately and inserted into the text input. If the value was, for a moment, 10/0/2014, the picker would shift the calendar to 09/30/2014, and plug that value into the text field. If I tried to edit the month, and the value was, for a moment, 1/7/2014, the picker would shift to January 7, 2014, and plug that value in to the text field.
You can see that behavior in this fiddle:
http://jsfiddle.net/krainey/nxhqerxg/10/
I had to update my binding with a special handler to detect focus, and bind a one-time blur event to get it to handle manual edits correctly.
$(element).on("changeDate", function (ev) {
var observable = valueAccessor();
if ($(element).is(':focus')) {
// Don't update while the user is in the field...
// Instead, handle focus loss
$(element).one('blur', function(ev){
var dateVal = $(element).datepicker("getDate");
observable(dateVal);
});
}
else {
observable(ev.date);
}
});
The fiddle referenced in the original answer has been updated to reflect this:
http://jsfiddle.net/krainey/nxhqerxg/
Here is what I Ended up
ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = {
autoclose: true,
format: 'yyyy-mm-dd',
}
//var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
//when a user changes the date, update the view model
ko.utils.registerEventHandler(element, "changeDate", function (event) {
var value = valueAccessor();
if (ko.isObservable(value)) {
var myDate = event.date;
var month = myDate.getMonth() + 1;
var monthText = month;
if (month < 10)
monthText = "0" + month;
var day1 = parseInt(myDate.getDate());
var dayText = day1;
if (day1 < 10)
dayText = '0' + day1;
value(myDate.getFullYear() + '-' + monthText + '-' + dayText);
}
});
},
update: function (element, valueAccessor) {
var widget = $(element).data("datepicker");
//when the view model is updated, update the widget
if (widget) {
widget.date = ko.utils.unwrapObservable(valueAccessor());
widget.setValue(widget.date);
}
}};
There is a much simpler way to get bootstrap-datepicker.js and knockout.js working together. Typically the initialization of the datepicker inputs is invoked during/after the page load. However when knockout.js updates the value binding, the datepicker is not updated correctly with the new value and so when you focus on the datepicker input it defaults to 01-Jan-2001.
All you have to do is to destroy and reinitialise the datepicker inputs after any knockout.js value bindings are updated as per the ViewModel method below, which sets up a mapped object to be edited.
self.showEditOrderForm = function (data) {
ko.mapping.fromJS(data, self.entity);
self.mode('edit');
$('#edit-dateordered').datepicker('destroy');
$('#edit-dateordered').datepicker({
format: 'dd-M-yyyy',
title: 'Select Date',
weekStart: 1,
todayHighlight: true,
autoClose: true,
endDate: '0d'
});
};