Using checkboxes to trigger various scripts, then clear - google-sheets-api

I have a Google Sheet set up with two buttons on the Form sheet, which are attached to two different scripts. They work perfectly on PC, but unfortunately, custom buttons still do not appear to work on the Google Sheets app for tablets. I was able to incorporate a workaround via a dropdown box, but that is still a bit finicky, so I'm wondering whether I could just switch both PC and tablet users to checkboxes instead.
If the checkbox in cell G3 is checked, the AUTOFILL script should run and the checkbox should be cleared; subsequently, if the checkbox in cell G5 is checked, the UPDATE script should run and its checkbox be cleared.
What would be the best way of doing this, now that checkboxes are a thing in Google Sheets?
Here is the code I am currently using, working for both the buttons and the dropdown:
function onEdit(e) {
if (e.range.getA1Notation() == 'D3') {
if (/^\w+$/.test(e.value)) {
eval(e.value)();
e.range.clearContent();
}
}
}
function AUTOFILL() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form');
var valueOfData = sheet1.getRange(sheet1.getLastRow(), 1).getValue();
sheet2.getRange('B3').setValue(valueOfData + 1);
}
function UPDATE() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Form");
var dataSheet = ss.getSheetByName("Data");
var values = formSS.getRange("B3:B6").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 4).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
var now = [new Date()];
var newData = data.concat(now)
dataSheet.getRange(row, 1, 1, 5).setValues([newData]);
formSS.getRange("B3:B6").clearContent()
}

A you correctly said, running scripts on button clicks does not appear to work on the Android mobile app. This is an issue that has already been reported (see this and this). A common workaround used to be using Android add-ons but they are now deprecated.
In order to make your script run using checkbox, one thing you can do is to modify your onEdit function. After the following modifications, it will check whether any of the checkboxes is enabled, run the appropiate function based on that, and then disable it again. You can see the updated onEdit function below:
function onEdit(e) {
var isAutofill = SpreadsheetApp.getActiveSheet().getRange("G3").getValue();
var isUpdate = SpreadsheetApp.getActiveSheet().getRange("G5").getValue();
if (isAutofill && isUpdate) {
Browser.msgBox("You cannot autofill and update at once!");
SpreadsheetApp.getActiveSheet().getRange("G3").setValue(false);
SpreadsheetApp.getActiveSheet().getRange("G5").setValue(false);
} else if (isAutofill) {
AUTOFILL();
SpreadsheetApp.getActiveSheet().getRange("G3").setValue(false);
} else if (isUpdate) {
UPDATE();
SpreadsheetApp.getActiveSheet().getRange("G5").setValue(false);
}
if (e.range.getA1Notation() == 'D3') {
if (/^\w+$/.test(e.value)) {
eval(e.value)();
e.range.clearContent();
}
}
}

Related

Datatable: when using 3000 records my datatable is getting loading slowly, and when click on buttton on change action not responding immediately

When I click on search button, my page getting freeze, alerts & masking are not working but when page loads completing alerts are popup.
Pleas help me on this
I have 3000 rows in a Datatable:
I Have two radio buttons
Show only Difference
All
When I click any one of button applyFitler function will get execute and executeFilter is filter function that executes when table is getting Draw,
What I expected is, when I click on any of Radio button, Mask with Please wait should show immediately, but it shows before one second (9th second) of returning results to Datatable. Total its taking 10 seconds to apply filter and return Datatable.
During these 10 seconds by browser page getting freeze
var applyFitler = function() {
alertBlock('Please wait..');
// clear the global search box
__DATATABLE.search('');
// set columnIndex to match data attribute of each column (used in our custom search while allowing moving of columns)
$('#devresult th').each(function(index) {
var headerText = $(this).data('col-header');
__TABLEHEADERS[headerText].columnIndex = $(this).data('column-index');
});
if (__DATATABLE != undefined) {
__DATATABLE.draw();
}
alertUnblock();
};
var executeFilter = function(settings, data, dataIndex, rowData, counter) {
var rows = __DATATABLE.rows({ 'search': 'applied' }).nodes();
var showRow= $("input[name=showRow]:checked").val();
if(showRow == "notshow") {
return false;
}
}
return true;
}

How to prevent closing of cell edit mode on validation errors with custom vue components in ag-grid

I have succesfully rendered my own component as the cellEditor and would like and on-leave I would like it to try to validate the value and prevent the closing if it fails.
If I look at this then https://www.ag-grid.com/javascript-grid-cell-editing/#editing-api there's cancelable callback functions for editing. But in this callback function is there a way to access the current instantiated component? I would think that would be the easiest way to handle this.
I'm using vee-validate so the validation function is async, just to keep in mind.
Use Full row editing.
Create a global variable like
var problemRow = -1;
Then Subscribe to this events:
onRowEditingStarted: function (event) {
if (problemRow!=-1 && event.rowIndex!=problemRow) {
gridOptions.api.stopEditing();
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
},
onRowEditingStopped: function (event) {
if (problemRow==-1) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
}
if (problemRow == event.rowIndex) {
if (event.data.firstName != "your validation") {
problemRow = event.rowIndex
gridOptions.api.startEditingCell({
rowIndex: problemRow,
colKey: 'the column you want to focus',
});
}
else{
problemRow=-1;
}
}
},
I had a similar issue - albeit in AngularJS and the non-Angular mode for ag-grid - I needed to prevent the navigation when the cell editor didn't pass validation.
The documentation is not very detailed, so in the end I added a custom cell editor with a form wrapped around the input field (to handle the niceties such as red highlighting etc), and then used Angular JS validation. That got me so far, but the crucial part was trying to prevent the user tabbing out or away when the value was invalid so the user could at least fix the issue.
I did this by adding a value parser when adding the cell, and then within that if the value was invalid according to various rules, throw an exception. Not ideal, I know - but it does prevent ag-grid from trying to move away from the cell.
I tried loads of approaches to solving this - using the tabToNextCell events, suppressKeyboardEvent, navigateToNextCell, onCellEditingStopped - to name a few - this was the only thing that got it working correctly.
Here's my value parser, for what it's worth:
var codeParser = function (args) {
var cellEditor = _controller.currentCellEditor.children['codeValue'];
var paycodeId = +args.colDef.field;
var paycodeInfo = _controller.paycodes.filter(function (f) { return f.id === paycodeId; })[0];
// Check against any mask
if (paycodeInfo && paycodeInfo.mask) {
var reg = new RegExp("^" + paycodeInfo.mask + '$');
var match = args.newValue.match(reg);
if (!match) {
$mdToast.show($mdToast.simple().textContent('Invalid value - does not match paycode format.').position('top right').toastClass('errorToast'))
.then(function(r) {
_controller.currentCellEditor.children['codeValue'].focus();
});
throw 'Invalid value - does not match paycode format.';
}
}
return true;
};
The _controller.currentCellEditor value is set during the init of the cell editor component. I do this so I can then refocus the control after the error has been shown in the toast:
CodeValueEditor.prototype.init = function (params) {
var form = document.createElement('form');
form.setAttribute('id', 'mainForm');
form.setAttribute('name', 'mainForm');
var input = document.createElement('input');
input.classList.add('ag-cell-edit-input');
input.classList.add('paycode-editor');
input.setAttribute('name', 'codeValue');
input.setAttribute('id', 'codeValue');
input.tabIndex = "0";
input.value = params.value;
if (params.mask) {
input.setAttribute('data-mask', params.mask);
input.setAttribute('ng-pattern','/^' + params.mask + '$/');
input.setAttribute('ng-class',"{'pattern-error': mainForm.codeValue.$error.pattern}");
input.setAttribute('ng-model', 'ctl.currentValue');
}
form.appendChild(input);
this.container = form;
$compile(this.container)($scope);
_controller.currentValue = null;
// This is crucial - we can then reference the container in
// the parser later on to refocus the control
_controller.currentCellEditor = this.container;
$scope.$digest();
};
And then cleared in the grid options onCellEditingStopped event:
onCellEditingStopped: function (event) {
$scope.$apply(function() {
_controller.currentCellEditor = null;
});
},
I realise it's not specifically for your components (Vue.js) but hopefully it'll help someone else. If anyone has done it a better way, I'm all ears as I don't like throwing the unnecessary exception!

Dojo - How to set "label" of togglebutton inside a grid from row.data.SOMEFIELD value?

i'm new to Dojo.
I have a "FullEditable" grid, with many columns, and one of them is a widget, it's a ToggleButton. This grid is used to show details of a purchase, so every line represents a product sold. When i click a button inside one of the columns it launches the product (dialog) browser and then the data of that product is passed to the grid. After some work i managed to display the button and being able to set it's label accordingly to the row.data.FIELD value received from that dialog.
But now i am editing that purchase and i need to be able to do the same, to be able to load the data from the preloaded array with data ("detalle") (as it's label) into the togglebutton, but nothing seems to work, not even the direct assignment of the widget or the row data or anything.
Here's a fragment of my code:
var grid = this;
var selectedRow = grid.row(i);
var cell = grid.cell(selectedRow, 'Moneda');
selectedRow.Moneda = detalle.MonedaItem; //didn't work
if(cell.row !== null && cell.row !== undefined && cell.row.data !== null && cell.row.data !== undefined)
cell.row.data.Moneda = detalle.MonedaItem; //didn't work
if(cell.element !== null && cell.element !== undefined){
cell.element.innerText = detalle.MonedaItem; //didn't work
cell.element.textContent = detalle.MonedaItem; //didn't work
if(detalle.MonedaItem === 'UF')
cell.element.widget.set('checked', true);
if(detalle.MonedaItem === 'CLP')
cell.element.widget.set('checked', false);
cell.element.widget.set('label', detalle.MonedaItem); //didn't work
cell.element.widget.set('value', detalle.MonedaItem); //didn't work
}
}
Whenever i set the value through the change event with "cell.element.widget.set('checked', boolean);" i get an error message from the editor, when it tries to get a cell but the variable is null, so it crashes.
The values of "label" and "value" of the widget, row.data en cell are perfectly set, BUT the grid DISPLAYS the "emptyValue" value of the widget and not the one that is actually set.
AFAIK, best way to change the grid data is to update the store/ collection that is associated with the grid and just invoke grid.refresh(). The new data will be loaded automatically.
The statement cell.row.data.Moneda = detalle.MonedaItem is actually changing the data in your store. Just refresh the grid after this and you are done!
Never try to set something in grid DOM element directly. Always work with store, renderCell and renderColumn. This will ensure consistency in store and grid attributes that reference the store.
I finally managed to get what i need through renderCell like this:
,{
id: 'Moneda',
field: 'Moneda',
label: "Moneda",
renderCell: function (object, value, node, options) {
try {
var button = new ToggleButton({
node: node,
isWidgetInGrid: true,
parameterName: 'codigoMoneda',
label: object.Moneda,
showLabel: true,
onChange: function(newValue){
var grid = this.getParent();
var row = grid.row(this.node);
var data = row.data;
if(this.get('label') === 'CLP')
{
data.Moneda = 'UF';
this.set('label','UF');
this.set('value', 'UF');
}
else
{
data.Moneda = 'CLP';
this.set('label','CLP');
this.set('value', 'CLP');
}
grid.getParent().getParent()._calcularTotales();
}
});
node.appendChild(button.domNode);
}
catch (ex) {
Debug.log(this.declaredClass, arguments, ex);
}
},
emptyValue: 'CLP',
autoSave: true
}

Interactive nodes in vis js network

When node is selected I want to add a icon on node and on icon click I want to give options to edit or deleted selected node. Is this possible or how to implement this in Vis js?
you can use the click event or nodeSelected.
like this:
network.on('click', function (properties) {
selection = properties.nodes
if (selection > 0) {
var node_sel = nodes.get([selection])[0];
if(node_sel['selected']){
alert('add you buttons');
}
else{
alert('change the style here');
node_sel['selected'] = true;
node_sel['shape'] = 'box';
nodes.update(node_sel);
var msg = JSON.stringify(nodes.get([selection]))
alert(msg);
}
}
});
see this plunker, instead of the alerts put your code.

Cycle Jquery UI Tab on "previous" and "next" button

I am using Jquery UI Tabs for my website.
<script type='text/javascript'>
//<![CDATA[
jQuery(window).load(function(){
jQuery('#myTabs').tabs({ fx: { opacity: 'toggle' }});
jQuery('.next-product').click(function(){
var jQuerytabs = jQuery('#myTabs').tabs();
var selected = jQuerytabs.tabs('option', 'selected');
jQuerytabs.tabs('select', selected+1);
});
jQuery('.previous-product').click(function(){
var jQuerytabs = jQuery('#myTabs').tabs();
var selected = jQuerytabs.tabs('option', 'selected');
jQuerytabs.tabs('select', selected-1);
});
As you can see that i have been using the previous next button to move from one tab to another.
My question is "When i click on next and if the last tab is open then automatically the first tab should get open, and similarly When i click on previous and if the first tab is open then automatically the last tab should get open"
Please help me out, i am stuck from over 3 days now and no solution. I have searched a lot on net but no solution for this.
You can count the number of .ui-tabs-panel elements.
jQuery(window).load(function() {
var $tabs = jQuery('#myTabs');
$tabs.tabs({
fx: {
opacity: 'toggle'
}
});
var amount = $tabs.find('.ui-tabs-panel').length;
jQuery('.next-product').click(function() {
var selected = $tabs.tabs('option', 'selected');
$tabs.tabs('select', selected + 1 === amount ? 0 : selected + 1);
});
jQuery('.previous-product').click(function() {
var selected = $tabs.tabs('option', 'selected');
$tabs.tabs('select', selected === 0 ? amount - 1 : selected - 1);
});
});
DEMO
Notes:
select your tab element already and re-use the selector var $tabs = jQuery('#myTabs');, it'll be more efficient
no need to re-call .tabs() on your click handlers