Im trying to get the parent object of a nested field that I'm editing.
Lets assume my column definition is like this:
columns:[
{title:"Name" + i, field:"user" + i + ".name", cellEdited : cellEditDone},
],
And my cellEditDone looks like this:
cellEditDone: function (cell) {
var rowData = cell.getRow().getData();
var value = cell.getValue();
}
Now as you can see the column definitions(s) may be dynamically generated based on how many manes should appear in a row.
So, when I finish editing the cell, I need to get the specific object (in this case the user object) that has been edited, and not just the name field.
Can I somehow get the parent of the cells field or can I somehow get additional custom data to the cellEditDone function for each row/cell as to identify the specific user having the name edited?
Well.
Been at it for the whole evening and 5 minutes after I post a question here, I find a solution..
It turns out that you can add custom data to the column definition;
columns:[
{title:"Name" + i, field:"user" + i + ".name", cellEdited : cellEditDone, userIndex : i},
],
and retrieve it like this in the editDone event :
var definition = cell.getColumn().getDefinition();
var theIndex = definition.userIndex;
Related
I have a jquery:datatable in my code where its columns are created dynamically in the C# based on some table records in SQL.
In this datatable, I use a custom button called "Save". I need to get the column names of the table here as I get the data in the rows but I couldn't find the correct syntax to get the column names.
...
text: 'Save',
action: function (e, dt, node, config) {
var json = JSON.stringify(dt.rows().data().toArray());
// how to get the columns??
// probably I need to use dt.columns().header() at some point?
}
...
I believe I need to use dt.columns().header() as it gives me tags with a lot of info, not sure how I can retrieve column name over there.
Any help would be appreciated.
With the method
table.columns().names();
I've found my own answer. Here it is:
var cols = ""
dt.columns().header().each(function (e, i) {
var col = jQuery(e).html();
cols += col + ",";
});
Thanks.
I have two sheets. Test Data has 3-4k entries of many columns of data and Order Changes has no data at all. I would like to search two specific columns on Test Data, a column of names and a column of yes or no. If column two of Test Data contains a 'yes' in the cell then the name of that person would be placed into a cell on order changes.
This is what I have so far:
function isThreshold(){
var data = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Test Data");
var cdata = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Order Changes");
var lc = data.getLastColumn();
var lookUp = data.getRange(1,6,3,2).getValues();
lookUp.forEach(var info in lookUp){
}
Logger.log(lookUp);
}
I probably shouldn't loop through that many entries but I don't know of any other way. Should I combine the forEach loop with an if loop to get the desired result or use some other method?
I believe your goal as follows.
You want to retrieve the values from the cells "F1:G" of sheet "Test Data".
You want to search yes from the column "G" and when the column "G" is yes, you want to put the value of the column "F" to the sheet "Order Changes".
Modification points:
SpreadsheetApp.getActiveSpreadsheet() can be declared one time.
In this case, you can retrieve the values from the range of "F1:G" + data.getLastRow() of "Test Data", and create the array for putting to the sheet "Order Changes", and put it.
When above points are reflected to your script, it becomes as follows.
Modified script:
function isThreshold(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getSheetByName("Test Data");
var cdata = ss.getSheetByName("Order Changes");
var valuesOfTestData = data.getRange("F1:G" + data.getLastRow()).getValues();
var valuesForOrderChanges = valuesOfTestData.reduce((ar, [f, g]) => {
if (g.toLowerCase() == "yes") ar.push([f]);
return ar;
}, []);
if (valuesForOrderChanges.length > 0) {
cdata.getRange(1, 1, valuesForOrderChanges.length, valuesForOrderChanges[0].length).setValues(valuesForOrderChanges);
// or cdata.getRange(cdata.getLastRow() + 1, 1, valuesForOrderChanges.length, valuesForOrderChanges[0].length).setValues(valuesForOrderChanges);
}
}
In this modified script, from your question, it supposes that the columns "F" and "G" are the value of name and yes or no.
References:
getRange(a1Notation) of Class Sheet
reduce()
I am trying to discern the index # of the pattern selected in the Combo-box. I need to pass this index value in order for another function to read from a file at the correct location. Essentially, selecting the a pattern in the combobox will let me do a lookup for specifications associated with the selected pattern based on the index. To the best of my knowledge the Vaadin Combobox does not have an index associated with the combobox items, but you are able to pass a different value than the displayed label: https://vaadin.com/docs/-/part/elements/vaadin-combo-box/vaadin-combo-box-basic.html (see: Using Objects as Items). This is solution I am trying to implement, however it gets tricky because I am dynamically populating the combobox items from a JSON file.
The code to dynamically populate the items:
paver = document.querySelector('#paver');
//alert('script executed');
patterns = [];
familyind=y;
$.getJSON('menu.json').done(function(data){
//alert('getJSON request succeeded!');
family = (data.gui[x].family[y].display);
for(ind = 0; ind < data.gui[x].family[y].pattern.length; ind++){
var patternLbl = data.gui[x].family[y].pattern[ind].name;
var patternObj = '{ pattern: { label: "' + patternLbl + '", value: ' + ind + ' } }';
patterns[ind] = patternObj;
}
document.getElementById("cb1").items=patterns;
})
.fail(function(jqXHR, textStatus, errorThrown)
{
alert('getJSON request failed! ' + textStatus);
})
.always(function() { }};
HTML for the ComboBox
<div id="patternSelect">
<template is="dom-bind" id="paver">
<div class="fieldset">
class="patterns" items="[[patterns]]" item-label-path="pattern.label" item-value-path="pattern.value"></vaadin-combo-box>
</div>
</template>
</div>
The output I get when I try to execute this is that the entire constructed string gets assembled into my selection choices. Theoretically, this should not have happened because the item-value-path and item-label-path were specified when declaring the combobox.
Screenshot of Output
It says: { pattern: { label: "A-3 Piece Random", value: 0 } }
WORKING TOWARDS A SOLUTION SECTION:
___________(April 27, 7:00pm)___________
Suggested solution to use,
var patternObj = { pattern: { label: patternLbl, value: ind } };
works fine in displaying labels:
However, I am using a trigger to detect when the value in the combo-box is changed and return the new value. Here is the code for the trigger:
// select template
var paver = document.querySelector('#paver');
// define the ready function callback
paver.ready = function () {
// use the async method to make sure you can access parent/siblings
this.async(function() {
// access sibling or parent elements here
var combobox = document.querySelector('#cb1')
combobox.addEventListener('value-changed', function(event) {
// FOR REFERENCE LOG ERRORS, THIS COMMENT IS ON HTML:215
console.log(event.detail.value);
patval = event.detail.value;
console.log(patval)
// Do stuff with fetched value
});
});
};
I have made the suggested change to using a 'value-changed' trigger. It works very well with two slight issues. First, it returns each of the console log calls twice (not sure why twice). Second, when I select the first combo-box item it returns my values but does not set the label as selected. This is not an issue with the other combo-box items, but the first item needs to be selected twice to have the label set. Please watch this short video for a demonstration: https://youtu.be/yIFc9SiSOUM. This graphical glitch would confuse the user as they would think they did not select a pattern when they know they had. Looking for a solution to make sure the label is set when the first item is selected.
You are setting a currently a String to patternObj while you should be setting an Object.
Try using either var patternObj = JSON.parse('{ pattern: { label: "' + patternLbl + '", value: ' + ind + ' } }'; or even simpler:
var patternObj = { pattern: { label: patternLbl, value: ind } };
Also, I would recommend initializing the patterns = [] inside the done callback to make sure you're not leaving any old items in the patterns when the data changes.
I help maintain a Google spreadsheet where new data is added via a HTML form.
When it comes to add new data the insertion point of the new data depends on one of the form fields (Application Received date).
The script finds where in the sheet the data should be inserted and does 3 things:
Inserts a blank row at the correct location
Copies the row above (so formulas and conditional formatting are copied)
Replaces the data in the cells from the copy with the values entered into the form
The issue is cells A to I are value based (populated from the form) and so are cells M to O, but cells J,K,L are calculations based on some cells in A to I.
This means I have to make 2 calls to getRange/setValues and sometimes the second call (the call to set cells M,N,O does not work. The result is a new row created with the correct data in cells A to I (and thus J,K,L) but cells M,N,O stay as whatever is in those cells in the row above.
Here is the relevant code.
// Assign object data for cells A to I
var newvalues = [
[ username, applyDate, maritalStatus, sponsorApprovalDate, processingOffice, inProcessDate, extraDocsRequestedDate, nonVisaExempt, decisionMadeDate ]
];
// Set cells A to I with data from form
sheet.getRange('A' + startingRowIndex + ':I' + startingRowIndex).setValues(newvalues);
// Now assign object data for cells M to O
newvalues = [
[ coprReceivedDate, location, notes ]
];
// Set cells M to O with data from form
sheet.getRange('M' + startingRowIndex + ':O' + startingRowIndex).setValues(newvalues);
As stated above the second sheet.getRange('...').SetValues() call fails to set the values.
Any ideas?
Instead of completely recalculating the locations of your output ranges, you could get an "anchor" point at the start of the row, then use the Range.offset() method to define additional ranges relative to the anchor.
// Assign object data for cells A to I
var newvalues = [
[ username, applyDate, maritalStatus, sponsorApprovalDate, processingOffice, inProcessDate, extraDocsRequestedDate, nonVisaExempt, decisionMadeDate ]
];
// Get range "anchor" for data from form
var newRow = sheet.getRange('A' + startingRowIndex );
// Set cells A to I with data from form
newRow.offset(0,0,newvalues.length,newvalues[0].length).setValues(newvalues);
// Now assign object data for cells M to O
newvalues = [
[ coprReceivedDate, location, notes ]
];
// Set cells M to O with data from form
newRow.offset(0,13,newvalues.length,newvalues[0].length).setValues(newvalues);
Struggling to find a bit of code to easily understand.
How do you add a row and clear all rows in a Dojo datagrid (version 1.4.2). Lets say the data is 2 columns with customerID and address.
I am using
dojo.data.ItemFileWriteStore
to store values in - but again not quite sure how this should be used.
It can't be that hard.
Cheers.
You can get the data store reference from the grid using grid.store, then you can use store.newItem() to create a new item in the store. This new item is added as a new row in the grid. For example, store.newItem({customerID : 1, address : "Somewhere"}).
To clear all the rows, you can either loop all the items in the data store and use deleteItem() to remove all the items, or use the internal function _clearData() in data grid to remove all the rows, or use setStore() to set a new empty store to the grid. I prefer to use a empty store to reset the grid.
The above answers are correct, but you also need to call save() on the write store to "commit" the change. When you save, a widget using the store (datagrid for example) will refresh itself.
Also, newItem() returns the new item you just created so if you don't want to pass an object to newItem just modify its return value, then save() the store.
Pseudo code:
var i = store.newItem({});
store.setValue(i,"newattribute1","new value");
store.setValue(i,"newattribute2","new value 2");
store.save();
Here is the relevant docs for ItemFileWriteStore which tell how to use newItem(), setValue(), and save().
Instead of deleteItem, you should use setStore(new ItemFileWriteStore()), but I suspect there is a memory leak when you do this, be careful. This makes a new blank store to be used with the grid.
I have finish one example about this... the code is here
//First we create the buttons to add/del rows
var addBtn = new dijit.form.Button({
id: "addBtn",
type: "submit",
label: "Add Row"
},
"divAddBtn");//div where the button will load
var delBtn = new dijit.form.Button({
id: "delBtn",
type: "submit",
label: "Delete Selected Rows"
},
"divDelBtn");
//Connect to onClick event of this buttons the respective actions to add/remove rows.
//where grid is the name of the grid var to handle.
dojo.connect(addBtn, "onClick", function(event) {
// set the properties for the new item:
var myNewItem = {
id: grid.rowCount+1,
type: "country",
name: "Fill this country name"
};
// Insert the new item into the store:
// (we use store3 from the example above in this example)
store.newItem(myNewItem);
});
dojo.connect(delBtn, "onClick", function(event) {
// Get all selected items from the Grid:
var items = grid.selection.getSelected();
if (items.length) {
// Iterate through the list of selected items.
// The current item is available in the variable
// "selectedItem" within the following function:
dojo.forEach(items, function(selectedItem) {
if (selectedItem !== null) {
// Delete the item from the data store:
store.deleteItem(selectedItem);
} // end if
}); // end forEach
} // end if
});