I'm working on a script that would copy a row from a big database and that way makes it easier to modify.
The main point would be to allow more editor to modify the database parallel. However, if I share the spreadsheet, other users get the following error: Script ... experienced an error. The user encounters this problem by scripts assigned to a button only. onEdit() runs just fine.
It's my first google script file, so I have really no idea that what's the problem and how should I solve it.
The whole code is here:
//copy the chosen row to the appropriate cells of the editor sheet
//if zero sets the cells to default
function copySelectedRow(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var shData=ss.getSheets()[0];
var shEdit=ss.getActiveSheet();
var idNumber = shEdit.getRange(1,2).getValue();
if(idNumber == 0) {
var arrayData = [["","","","","","","","","","","","","","","","","","","","","","","","",""]];
} else {
var rowNumber=findRow(idNumber);
if(rowNumber == -1) {
SpreadsheetApp.getUi().alert('Nincs ilyen betegszam!');
return;
}
var range1=shData.getRange(rowNumber,1,1,shData.getLastColumn());
var arrayData=range1.getValues();
}
var arrayDataT = new Array(new Array);
var arr = new Array(new Array);
var arrT = new Array(new Array);
arrayDataT = transpose(arrayData);
arrT = arrayDataT.slice(1,6);
arr = transpose(arrT);
shEdit.getRange(5,1,1,5).setValues(arr);
shEdit.getRange(2,4).setValue(arrayData[0][6]);
arrT = arrayDataT.slice(7,11);
shEdit.getRange(7,2,4).setValues(arrT);
arrT = arrayDataT.slice(7,11);
shEdit.getRange(7,2,4).setValues(arrT);
shEdit.getRange(7,3).setValue(arrayData[0][11]);
arrT = arrayDataT.slice(12,16);
shEdit.getRange(7,4,4).setValues(arrT);
arrT = arrayDataT.slice(16,20);
shEdit.getRange(12,2,4).setValues(arrT);
shEdit.getRange(12,3).setValue(arrayData[0][20]);
arrT = arrayDataT.slice(21,25);
shEdit.getRange(12,4,4).setValues(arrT);
}
//trasnspone a 2D array
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
//save the cells to the database, checks and writes out if the editor is sure or unsure
function saveData() {
var app = SpreadsheetApp;
var shData = app.getActiveSpreadsheet().getSheets()[0];
var shEdit = app.getActiveSpreadsheet().getActiveSheet();
var idNumber = shEdit.getRange(1,2).getValue();
var row = findRow(idNumber);
if(row == -1) {
SpreadsheetApp.getUi().alert('Nincs ilyen betegszam!');
return;
}
var arr = new Array;
var arrT = new Array(new Array());
var arrayData = new Array(new Array());
var tempArray = new Array(new Array());
arrT = shEdit.getRange(7,2,4).getValues();
arr = transpose(arrT);
arrayData.push(arr);
arrT = shEdit.getRange(7,3).getValue();
tempArray[0][0] = arrT;
arrayData.push(tempArray);
arrT = shEdit.getRange(7,4,4).getValues();
arr = transpose(arrT);
arrayData.push(arr);
arrT = shEdit.getRange(12,2,4).getValues();
arr = transpose(arrT);
arrayData.push(arr);
arrT = shEdit.getRange(12,3).getValue();
tempArray[0][0] = arrT;
arrayData.push(tempArray);
arrT = shEdit.getRange(12,4,4).getValues();
arr = transpose(arrT);
arrayData.push(arr);
tempArray = new Array(new Array);
var count = 0;
for(var i=1; i<arrayData.length; i++){
for(var j=0; j<(arrayData[i][0].length); j++){
tempArray[0][count]=arrayData[i][0][j];
count++;
}
}
shData.getRange(row,8,1,18).setValues(tempArray);
var sure = shEdit.getRange(20,6).getValue();
if(sure) {
shData.getRange(row, 7).setValue("KÉSZ");
shEdit.getRange(2,4).setValue("KÉSZ");
} else {
shData.getRange(row, 7).setValue("BIZONYTALAN");
shEdit.getRange(2,4).setValue("BIZONYTALAN");
}
}
//returns the row number of the id value in the database
function findRow(idNumber) {
var app = SpreadsheetApp;
var shData = app.getActiveSpreadsheet().getSheets()[0];
var matchArray = shData.getRange("A:A").getValues();
for(var count=0; count<matchArray.length; count++){
if(matchArray[count][0]==idNumber) return count+1;
}
return -1;
}
//runs if the id cell is modified
function onEdit(e) {
var range = e.range;
var columnOfCellEdited = range.getColumn();
var rowOfCellEdited = range.getRow();
if (columnOfCellEdited === 2 && rowOfCellEdited === 1) {
copySelectedRow();
collision();
}
};
//increment the value of id by one
function incrementByOne() {
var app = SpreadsheetApp;
var targetSheet = app.getActiveSpreadsheet().getActiveSheet();
var tempNumber = targetSheet.getRange(1,2).getValue();
targetSheet.getRange(1, 2).setValue(tempNumber+1);
copySelectedRow();
collision();
}
//decrement the value of id by one
function decrementByOne() {
var app = SpreadsheetApp;
var targetSheet = app.getActiveSpreadsheet().getActiveSheet();
var tempNumber = targetSheet.getRange(1,2).getValue();
targetSheet.getRange(1, 2).setValue(tempNumber-1);
copySelectedRow();
collision();
}
//writes out if more editors are editing the same line
function collision(){
var ss=SpreadsheetApp.getActiveSpreadsheet();
var allSheets=ss.getSheets();
var idArray = new Array();
var temp;
for(var i=1; i<allSheets.length; i++){
temp = allSheets[i].getRange(1,2).getValue();
idArray.push(temp);
}
var collisionArray = new Array();
for(var i=0; i<idArray.length; i++){
for(var j=i+1; j<idArray.length; j++){
if(idArray[i] == idArray[j]){
collisionArray.push(i);
collisionArray.push(j);
}
}
}
for(var i=1; i<allSheets.length; i++){
allSheets[i].getRange(1,3).setValue("");
}
for(var i=0; i<collisionArray.length; i++){
allSheets[collisionArray[i]+1].getRange(1,3).setValue("SZERKESZTÉS ALATT");
}
}
So if I click the drawing that is associated with incrementByOne, it will give an error, but if I just change the cell, onEdit() can call the same functions easily.
(Sorry for the long code, I don't know which part could be important. If you tell me, I'll make it shorter.)
The solution:
If I share the code with a link, an anonymous editor can not use every script, because of authentication issues (don't ask why it isn't a problem by onEdit() ). Also, if the editor logs in into his/her gmail account and accepts everything, the script will become runable (but maybe a bit slower than on the owners account).
I have this block as UI :
<textbox id="style-search" flex="1" type="search" timeout="250" dir="reverse"/>
and this is the onload function:
var listbox = document.getElementById("style-listbox");
var searchbox = document.getElementById("style-search");
var styles = Zotero.Styles.getVisible();
var index = 0;
var nStyles = styles.length;
var selectIndex = null;
var searchValue = searchbox.value;
if (searchValue) {
for (var i = 0; i < nStyles; i++) {
if (styles[i].title.match(searchValue)) {
var itemNode = document.createElement("listitem");
itemNode.setAttribute("value", styles[i].styleID);
itemNode.setAttribute("label", styles[i].title);
itemNode.setAttribute("id", styles[i].title);
if (i % 2 === 0) {
itemNode.setAttribute("class", "backG");
} else {
itemNode.setAttribute("class", "backY");
}
listbox.appendChild(itemNode);
if (styles[i].styleID == _io.style) {
selectIndex = index;
}
index++;
}
}
}
i need this: when i type some string in search box i want to filter all my style base on my style list with that string. i try above code but it doesn't work.
I am working on a table that I need to be able to move rows up and down.
The problem is that I cannot re-insert the row before the previous or next row, because my application relies on the names of the input fields to stay in the same order.
My solution is to swap the values of the input fields, which works, but my code is very ugly and repetitive.
$(document).ready(function(){
$(".up,.down").click(function(){
var row = $(this).parents("tr:first");
var rowdata1 = row.find('.rowdata1').val();
var rowdata2 = row.find('.rowdata2').val();
var rowdata3 = row.find('.rowdata3').val();
var rowdata4 = row.find('.rowdata4').val();
var rowdata5 = row.find('.rowdata5').val();
if ($(this).is(".up")) {
var tmp1 = row.prev().find('.rowdata1').val();
var tmp2 = row.prev().find('.rowdata2').val();
var tmp3 = row.prev().find('.rowdata3').val();
var tmp4 = row.prev().find('.rowdata4').val();
var tmp5 = row.prev().find('.rowdata5').val();
row.prev().find('.rowdata1').val(rowdata1);
row.prev().find('.rowdata2').val(rowdata2);
row.prev().find('.rowdata3').val(rowdata3);
row.prev().find('.rowdata4').val(rowdata4);
row.prev().find('.rowdata5').val(rowdata5);
row.find('.rowdata1').val(tmp1);
row.find('.rowdata2').val(tmp2);
row.find('.rowdata3').val(tmp3);
row.find('.rowdata4').val(tmp4);
row.find('.rowdata5').val(tmp5);
//row.insertBefore(row.prev());
} else {
var tmp1 = row.next().find('.rowdata1').val();
var tmp2 = row.next().find('.rowdata2').val();
var tmp3 = row.next().find('.rowdata3').val();
var tmp4 = row.next().find('.rowdata4').val();
var tmp5 = row.next().find('.rowdata5').val();
row.next().find('.rowdata1').val(rowdata1);
row.next().find('.rowdata2').val(rowdata2);
row.next().find('.rowdata3').val(rowdata3);
row.next().find('.rowdata4').val(rowdata4);
row.next().find('.rowdata5').val(rowdata5);
row.find('.rowdata1').val(tmp1);
row.find('.rowdata2').val(tmp2);
row.find('.rowdata3').val(tmp3);
row.find('.rowdata4').val(tmp4);
row.find('.rowdata5').val(tmp5);
//row.insertAfter(row.next());
}
});
});
I created a fiddle: http://jsfiddle.net/29T7V/
I would really appreciate any suggestions on how to simplify my code.
Any ideas on how to update my code to handle x amount of inputs in the rows would be absolutly awesome! TIA!
Something like this maybe
$(document).ready(function () {
$(".up, .down").on('click', function () {
var row = $(this).closest('tr').first(),
way = $(this).hasClass('up') ? 'prev' : 'next';
for (var i=1; i<6; i++) {
var sel = '.rowdata'+i,
tmp1 = row.find(sel).val(),
tmp2 = row[way]().find(sel).val();
row.find(sel).val(tmp2);
row[way]().find(sel).val(tmp1);
}
});
});
FIDDLE
Something wich would work with any number of columns:
$(document).ready(function () {
$(".up, .down").click(function () {
var $row = $(this).closest("tr"),
$swap = $row[$(this).is('.up') ? 'prev' : 'next']();
if (!$swap) return;
$row.find('td').each(function() {
var $input = $(this).find('input, select'),
$swapInput, $swapVal;
if ($input.length) {
$swapInput = $swap.children('td:eq(' + this.cellIndex + ')').find('input, select');
$swapVal = $swapInput.val();
$swapInput.val($input.val());
$input.val($swapVal);
}
});
});
});
Demo: http://jsfiddle.net/29T7V/
I am looping through an array and getting the data that I need.
for (var i = 0; i < finalArray.length; i++) {
var merchName = finalArray[i].merchName;
var amName = finalArray[i].amName;
var amEmail = finalArray[i].amEmail;
var txnID = finalArray[i].transID;
var transAccount = finalArray[i].transAccount;
}
What I am trying to do at this point is only show unique data in the loop.
For example var transAccount could be in the array 5 times. I only one to display that in my table once. How can I go about accomplishing this ?
Final Array is constructed like so; just as an object:
finalArray.push({
transID: tmpTrans,
transAccount: tmpAccount,
amEmail: amEmail,
merchName: merchName,
amPhone: amPhone,
amName: amName
});
var allTransAccount = {};
for (var i = 0; i < finalArray.length; i++) {
var merchName = finalArray[i].merchName;
var amName = finalArray[i].amName;
var amEmail = finalArray[i].amEmail;
var txnID = finalArray[i].transID;
var transAccount = finalArray[i].transAccount;
if(allTransAccount[finalArray[i].transAccount]) {
var transAccount = '';
}
else {
allTransAccount[transAccount] = true;
}
}
var merhcData = {};
var amName = {};
// and so on
for (var i = 0; i < finalArray.length; i++) {
merchData[finalArray[i].merchName] = finalArray[i].merchName;
amName[finalArray[i].amName] = finalArray[i].amName;
// and so on
}
If you are sure, that data in merchName will never be equal amName or other field - you can use one data object instead of several (merchData, amName...)
What you want is likely a Set. (see zakas for ES6 implementation. To emulate this using javascript, you could use an object with the key as one of your properties (account would be a good bet, as aperl said) which you test before using your raw array.
var theSet={};
for (var i = 0; i < finalArray.length; i++) {
var transAccount = finalArray[i].transAccount;
var merchName = finalArray[i].merchName;
var amName = finalArray[i].amName;
var amEmail = finalArray[i].amEmail;
var txnID = finalArray[i].transID;
if(!theSet[transAccount]){
//add to your table
theSet[transAccount]===true;
}
This will prevent entries of duplicate data.
I have one multiselect listbox in my HTMl.
I want to get values of selected items of listbox in javascript
My html code:
<select id="schools" size="5" multiple="multiple">
<option value="352">Byskovskolen</option>
<option value="355">Heldagsskolen Specialtilbud</option>
<option value="372">Plejecenter Solbakken</option>
</select>
My Javascript code:
function getData()
{
var allSchools = [];
var s = document.getElementById("schools");
alert("schools lenght " + s.options.length);
for (var i = 0; i < s.options.length; i++) {
if (s.options[i].selected == true) {
var schoolid = s.options[i].value;
alert(s.options[i].value);
allSchools.push(schoolid);
}
}
}
Values can be seen alerted with alert box but not getting stored in variable.
How can I store it in variable.
It works fine if you comment/uncomment the right lines. Try this:
function getData() {
var allSchools = [];
var s = document.getElementById("schools");
for (var i = 0; i < s.options.length; i++) {
if (s.options[i].selected == true) {
var schoolid = s.options[i].value;
allSchools.push(schoolid);
}
}
console.log(allSchools);
}
DEMO: http://jsfiddle.net/4qYht/1/
Uncommented one line (var schoolid) and added a print out for the allSchools variable.
function getData()
{
var allSchools = [];
var s = document.getElementById("schools");
alert("schools lenght " + s.options.length);
for (var i = 0; i < s.options.length; i++) {
if (s.options[i].selected == true) {
var schoolid = s.options[i].value;
allSchools.push(schoolid);
}
}
console.log(allSchools);
}
uncomment the schoolid assignment line
var schoolid = s.options[i].value;
allSchools.push(schoolid);
or
use allSchools.push(s.options[i].value); instead of allSchools.push(schoolid);
You have commented out the main line ,which would store the value in a variable.
// var schoolid = s.options[i].value;
apart from that rest of your code is perfect.
here is the corrected code :
function getData()
{
var allSchools = [];
var s = document.getElementById("schools");
alert("schools lenght " + s.options.length);
for (var i = 0; i < s.options.length; i++) {
if (s.options[i].selected == true) {
// var schoolid = s.options[i].value;
alert(s.options[i].value);
allSchools.push(schoolid);
}
}
}
Happy coding:)