I'm attempting to assign items to an array on a users action, so for example, user clicks "Add", this will add the selected id into the relevant section of the array.
The array won't be created at first so I set up an empty array:
var Options={};
On the users click, I then want to assign a key to match the option selected from a drop down so I can use this as a reference later on.
E.g. When the user clicks plus on a record, the option selected from a drop-down is 2. The id of the record they selected is say 5.
I'd like to structure my array like the following:-
[key e.g drop down option]
=> 'records' => array [record_id]
Each time the user clicks plus next to a record, the id is appended to the correct array based on the drop down selected option.
[option 1] => 'publication_date' = 12/09/2010, 'records' => [1, 2, 4]
[option 2] => 'publication_date' = 15/09/2010, 'records => [1, 3, 5]
etc, each option from the select box has a publication date and a series of records the user can assign to it.
You can do something like this:
function AddItem(key, value) {
if(Options[key]) Options[key].push(value);
else Options[key] = [value];
}
For example doing this:
AddItem(2, 5);
AddItem(2, 6);
Would result in Options being:
{ 2: [5, 6] }
You can give it a try/play with it here.
An object in javascript is good to store a one key dataset not various keys.
ie:
var records = {'12/09/2010':[1, 2, 4], '15/09/2010':[1, 3, 5]}
To get the records for the 15/09: records['15/09/2010']
Add a new record for a date: records['15/09/2010'].push(6)
If the date change, you need to do something like:
records['17/09/2010'] = records['15/09/2010']; delete records['15/09/2010']
The user is not able to change both at the same time(date and add) and you should do both update actions separately.
Now if you plan to have more keys, you should use an array of objects:
var records = [
{publication_date:'12/09/2010', records:[1, 2, 4], ..., otherProp='...'},
...
];
And for each change, loop on the array, find the relevant item and change it.
Related
I'm trying to use Google Apps Script to filter only exact matches. I've seen similar questions, but I can't seem to apply them to my situation.
On one sheet, I have a table of information which has the item name in column A, its' ingredient in column B, and its' quantity in column C. Column A contains items named Test and Test 2. When I filter for Test 2, I get results of both Test and Test 2. Here is the code I'm using:
var costSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Cost');
var ingSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Recipe Ingredient');
// Create list of items to filter from the full list
var rows = costSheet.getLastRow();
var itemList = costSheet.getRange(2, 1, rows - 1).getValues();
// Convert itemList to array to be used in filter
itemList = itemList.join();
// Get full non-filtered data
var fullList = ingSheet.getRange('A2:C514').getValues();
// Apply filter criteria
function checkMatch(item) {
return itemList.indexOf(item[0]) != -1;
}
filterList = fullList.filter(checkMatch);
// Clear target location, then place filtered data
costSheet.getRange('C2:E514').clearContent();
costSheet.getRange(2, 3, filterList.length, 3).setValues(filterList);
I don't have any trouble getting accurate results for multiple items from all three columns, and the only issue I have is when I try to filter an item that begins with the name of another item in the full list (e.g. filtering for Test 2 returns both Test and Test 2, when I want it to just return Test 2).
I am new to working with Google Apps Script/Javascript, hence the 'amateur' coding.
Explanation:
You are very close!
The issue is related to this line:
itemList = itemList.join();
Assuming that itemList = [["Test 2"],["Test 3"]] as a result of the getValues() method.
If you apply join you are converting the above array into the following string:
Test 1,Test 2
Therefore itemList.indexOf("Test") will return 0 which means your filter function will evaluate to true, but you don't want that since Test is not part of your array. You are mistakenly using the indexOf method of strings instead of the indexOf method of arrays.
Having said that, your goal is to use the the indexOf method of arrays. In order to do so, itemList needs to be an array and not a string.
To convert a 2D array [["Test 2"],["Test 3"]] into a 1D array [Test 1, Test 2] you can use flat.
Solution:
Change:
itemList = itemList.join();
To:
itemList = itemList.flat();
Improved Solution:
Going for the extra mile, you can shorten your code and make it more JavaScript modern like that:
function shorterFunction(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const costSheet = ss.getSheetByName('Cost');
const ingSheet = ss.getSheetByName('Recipe Ingredient');
const itemList = costSheet.getRange(2, 1, costSheet.getLastRow() - 1).getValues().flat();
const fullList = ingSheet.getRange('A2:C514').getValues();
const filterList = fullList.filter(r=>itemList.includes(r[0]))
costSheet.getRange('C2:E514').clearContent();
costSheet.getRange(2, 3, filterList.length, 3).setValues(filterList);
}
In this solution, I used an arrow function and includes.
I am using a dropdown that lists a data set.
I created a treeBoxValue variable to assign a predefined dropdown value. Thus, when I open the dropdown, the elements that contain the value of the variable treeBoxValue are checked.
My problem is that the presentation of these default values should contain the name and not the value.
Can someone help me to show only the names and not the values?
DEMO
Problem: The dropdown shows the values and not the name :(
When I open the dropdown, the values change to the name. I intend to get the names right at the beginning.
Note: If the dropdown did not open, refresh only the preview page.
Change this line:
treeBoxValue = ["1", "2"];
to this:
treeBoxValue = [1, 2];
In your Books array the field idBook is numeric.
Books = [
{
idBook: 1,
name: "name1"
},
{
idBook: 2,
name: "name2"
},
{
idBook: 3,
name: "name3"
}
];
I have an array that represents a table like this:
table = [['john', 'male', 24, '12/12/12'], ['jane', 'female', 24, 12/12/12]]
I want to let the user choose which column they want, so later they can make a pdf report with the columns they chose, I think making an object like this is the best way to get that data, I might be wrong of course haha.
Let's say the user wants the following data on the report header: name, age, date, I want an object like this:
userHeader = { name: 'John', age: 24, date: '12/12/12'}
So I can make the next report:
Report #1234
|-------------------------------|
|Name: John Date: 24/12/12 | <-Header
|Age: 24 |
|-------------------------------|
|some data | <--Body
| .... |
|-------------------------------|
I have an array with the columns the user wants that stores it index, for example if the user wants the columns 1 and 2, the array is this:
var userColumns = [1,2]
How can I approach this problem? How would you do it?
EDIT: I put the wrong table,. this are the tables:
table1 = [['john', 'male', 24, '12/12/12', 1], ['john', 'male', 24, 01/05/12, 1]]
table2 = [['john', 'male', 24, '12/07/12', 2], ['john', 'male', 24, 05/05/12, 2]]
To get some context, I have a CSV file with multiple columns and rows, each row has a different codeItem, this codeItem can be repeated in multiple rows or not, what i do is create multiple tables that have the same code report, for example if the CSV data has 10 rows, 5 with an codeItem:1 and the other 5 with codeItem: 2, I create 2 tables, one with all the rows that have the codeItem 1 and another with a codeItem 2, then I would make a report for each codeItem, in this case 2 reports, so each table has some rows that have the same data on some columns.
The user columns is what columns the user chose to appear on the report, I have an array with the header columns:
var headers = ['name', 'sex', 'age', 'date', 'codeReport']
What I do is match the index on the header array to the userColumns, lets say the user wants the name and age headers, the user header is:
userHeader = [0, 2]
I know it sounds confusing and it really is.
First of all, if you want to use objects for storing data from an given array, you need I routine to convert them. Therefor I allways create an empty object o = {}, and with o["prop"] = value can this object be filled. The same as o.prop = value.
let headers = ['name', 'sex', 'age', 'date', 'codeReport'];
function createObjectFromArray(array, indexes)
{
let result = {};
for(let index of indexes)
{
result[headers[index]] = array[index];
}
return result;
}
let recordObject = createObjectFromArray(['john', 'male', 24, '12/12/12', 1], [1, 2]);
//Object {sex: "male", age: 24}
With the help of the ECMAScript 6 class Map, it is possible to link an object to any data. Or you can use IndexedDB.
let reportDataBase = new Map();
reportDataBase.set(recordObject, "somedata");
reportDataBase.get(recordObject); // "somedata"
If you want to iterate through all tables (table 1 has code item 1, table 2 has code item 2, ...), you need an object, which is iterable. I recommend an array.
let tables = [table1, table2];
let selectedColumns = [1, 2];
for(var report = 0; report != tables.length; report++)
{
console.log("report : " + (report + 1));
tables[report].forEach(function(item)
{
console.log(createObjectFromArray(item, selectedColumns));
});
}
I think a better way to storage in-memory data and generate different reports, is to use a data structure like this:
var reports = [
[['john', 24, "somedata1"], ['lara', 22, "somedata2"]],
[['mark', 21, "somedata3"], ['eve', 25, "somedata4"]]
];
But its a bad idea, to storage all personal data in a open browser. To much ressources for showing one record and the question is: Wants the person that his data is public?
One solution is: frontend <-> node.js
You just need an association of table headers with array of user data like
ReportHeaderAssociation = {
"0":Name",
"1":Age",
....
}
So when you got columns that users want( here [1,2] ) you can get title from association object and value by accessing array element.
Like , userdata[1] will give you second element from data which is gender. Likewise all elements.
In short: a single object with relativity will do the job no need to run long loops to convert array to object.
You need a mapping for the column names, for example with the same indexes as the data and a filter for which columns you want.
After that map and reduce are your friends ;)
var table = [
['John', 'male', 24, '12/12/12'],
['Jane', 'female', 22, '11/11/11']
];
var columnMapping = ['name', 'gender', 'age', 'date'];
var getData = function(data, columnNames, columnFilter) {
return data.map(function(item) {
return item.reduce(function(obj, item, idx) {
if (columnFilter.indexOf(idx) > -1) {
obj[columnNames[idx]] = item;
}
return obj;
}, {});
});
}
// age and gender
console.log(getData(table, columnMapping, [1, 2]));
// name and date
console.log(getData(table, columnMapping, [0, 3]));
// name, age and date
console.log(getData(table, columnMapping, [0, 2, 3]));
// name, age and date only if name is John
console.log(getData(table, columnMapping, [0, 2, 3]).filter(function(item) {
return item.name === 'John';
}));
This is what I've constructed so far: https://plnkr.co/edit/fnhKUhuTYjUTQgJLnZoT?p=preview
I want to display a value in the input textbox that depends on the user's 2 choices from the 2 dropdown menus. I want that value to come from the values array here:
var values = [1, 2, 0.1, 1, 3, .2, 2, 3,.3];
If the 1st choice is 1 and the 2nd choice is 2, then I want the input textbox to display 0.1. And vice-versa, so if the 1st choice is 2 and the 2nd choice is 1 then I want 0.1 to be the output.
And I want nothing to happen if the user chooses the same value for both menus. So if the user chooses 2 for both menus, then I want there to be no output
How can I program this?
EDIT: I should probably first convert the values array to a hashmap like this:
var values = [(1, 2): 0.1, (1, 3): .2, (2, 3): .3];
I hope you won't mind me using jQuery in my solution since you had it included in your Plunk.
var $selects = $('select');
var $output = $('#pred');
First I will create a map of input pairs to output values.
var values = {
'1,2': 0.1,
'1,3': 0.2,
'2,3': 0.3
};
Next, I will listen for a change event on the select menus. In my change handler, I will map the values of the selects into an array of numbers. Next, by sorting and joining this array, I should end up with a stringed pair of numbers in ascending order and delimited by a comma; a key, just like the keys in my values object.
Finally, I will set the value of $output to the value of values at the resultant key. If values[key] is undefined, I will default to an empty string.
$selects.on('change', function () {
var key = $selects.map(function (index, el) {
return Number($(el).val());
})
.get()
.sort()
.join(',');
$output.val(values[key] || '');
});
so i'm sitting here for hours and now i have to get the Eyes of the Internet to help me out...
So i'm trying to create a Shift Plan. I created a Table (each cell a jQuery Dropdown button with the possible Shifts). on every selection i write the selected Shifts into an array.
The following code snippet is how i do that. I need this in the on click because it will show the total shift time in n extra field.
Later i want save the arrays to a Database an because of that i need to access the calFirstRow array for each employee.
var calFirstRow = [,];
$(document).ready(function(){
$('.dropdown-menu a').on('click', function(){
// Do the following stuff for every Employee
$.each( jqEmployees, function(index, value){
var name = value['NAME'];
// create array from first row
$( ".first-row-"+ name +" td button" ).each(function( index ) {
calFirstRow[name, index] = $( this ).text();
});
});//End each Employee
});//End Dropdown click
Here i try to Access the array
});//End ready
the problem is, no matter what i do, in every calFirstRow[name] i get the array from the last Employee.
If i print the Array i get something like [User1: Array, User2: Array] but in each, User1 and 2 is the data of User2 saved...
Im new to jQuery and i maybe miss somethin really fundamental....
It looks like you're trying to treat calFirstRow as a two dimensional array, but the way you're accessing it doesn't make any sense. If you pop open your browser's development console and type [,], you'll see this:
> [,]
< [undefined × 1]
It's got only a single dimension, and JavaScript treats the comma as coming after an element, which you haven't provided, so you have an array containing a single undefined.
The next problem happens when you access calFirstRow[name, index]. Arrays can only be accessed by a single integer index, and JavaScript doesn't know what to do with name, so it ignores it and just uses index:
> a = ['a', 'b', 'c']
> a[1, 2]
< 'c' // The element at index 2
> a[2, 0]
< 'a' // The element at index 0
The result is that your loops aren't creating a two dimensional array that matches your table, they're just overwriting calFirstRow again and again, which is why your last user's data ends up in it. It looks like it's in every row, but really when you access calFirstRow['User1', 0] or calFirstRow['User2', 0], you're just accessing calFirstRow[0] twice.
Since you're trying to index by the employee's name, and then their column in the table, I think you want to start with an object. calFirstRow doesn't seem like the name for what you really want, so let's call it shiftData:
var shiftData = {}
The keys in the object will be your employees' names, and the values will be their array of shifts. For example:
> shiftData['Kristjan'] = [1,2,3]
< [1, 2, 3]
> shiftData['Joel'] = [4,5,6]
< [4, 5, 6]
> shiftData
< Object {Kristjan: Array[3], Joel: Array[3]}
Joel: Array[3]
0: 4
1: 5
2: 6
length: 3
Kristjan: Array[3]
0: 1
1: 2
2: 3
length: 3
In your click handler, you can map over each employee's row in the table and set their named entry to the result.
$.each( jqEmployees, function(employeeIndex, value){
var name = value['NAME'];
shiftData[name] = $( ".first-row-"+ name +" td button" ).map(function( columnIndex ) {
return $( this ).text();
});
});
This will result in a shiftData object like I showed in the console above. Each iteration of map returns the text of the td button in the user's row and column. Those values are aggregated into an array and assigned to shiftData[name].