JQuery Access Arrays - Logical mistake possible - javascript

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].

Related

How to filter array for only exact match in Google Apps Script/Javascript

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.

Display value depending on selected values from 2 Dropdown menus in Javascript?

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] || '');
});

AngularJS: add, remove and reorder items controlled by array

I have an ng-repeat in a table. There are several of these tables inside a larger table. Each row has buttons for "add another" (which I have working) and remove current row/move row up-down (which I don't).
They are created with an array, each group in the table has its own array, with one member to start.
vm.choices1 = [{ id: 'choice1' }];
vm.choices2 = [{ id: 'choice1' }];
vm.choices3 = [{ id: 'choice1' }];
Clicking the plus button passes the current array and pushes a new item onto it, thus adding a repeater.
vm.addNewChoice = function(arr) {
var newItemNo = arr.length + 1;
arr.push({
'id': 'choice' + newItemNo
});
};
This works fine. Of course, now I have been asked to add the delete button and up/down buttons.
I get in concept what I need to do: I suppose somehow when the delete button is clicked I need to pass that index number to a delete function and pop that index from the array thats passed:
vm.deleteChoice = function(arr) {
arr.splice(index, index+1); //??
};
But I'm not sure how to get and pass the clicked index to the function. I used to know how to do this in jQuery, but not in Angular. If I can get the index of the clicked item into my function, I'm sure I can figure out the u/down buttons from there too.
Basic punker: http://plnkr.co/edit/WPdnmYbDSXC0LsbeMduM?p=preview
The directive ng-repeat creates a scope for every item that it iterates through. Part of the data assigned to this scope is the attribute $index which will be equal to the index in the array of the item/object.
Source: https://docs.angularjs.org/api/ng/directive/ngRepeat

Order by sorted array

I have a page that contains a table like the following (automatically sorted by "Name" column)
Name Open Num Total Num
-----------------------------------
Doe, John 0 0
Smith, Sarah 4 3
Tyler, Rose 7 8
The second tr would look like this:
<tr id="1"><td class="N">Smith, Sarah</td><td class="O">4</td><td class="T">3</td></tr>
Where the row ID is a counter (first row = 0, second = 1, third = 2, etc.) and the cell class is to grab the column using jQuery ($(".O") gives Open Num column)
I'm trying to get the table to sort based off of the numerical columns (Open Num and Total Num). So output would look like this (sorted by Open Num or Total Num):
Name Open Num Total Num
-----------------------------------
Tyler, Rose 7 8
Smith, Sarah 4 3
Doe, John 0 0
So far, I store the numbers into an array arrQuick and I store the row number in a different array rowCount. I then use the Quick Sort method to sort the data, at the same time sorting the second array, which works perfectly. So now I have the sorted data and the order that my rows should be in.
The Problem
I cannot figure out how to get the table rows to update correctly.
So far I have this.
for(var i=0;i<rowCount.length;i++){
var tmpHolder=$("#"+i).html();
$("#"+i).html($("#"+rowCount[rowCount.length-(i+1)]).html());
$("#"+rowCount[rowCount.length-(i+1)]).html(tmpHolder);
}
When stepping through I can see that initially the updating is working. However, eventually it gets to some point rows are getting updated to places they shouldn't be and I'm not sure why.
You can sort the rows based on the values of table cells. The following method accepts a className of the cells and sorts the rows based on the text contents of that cells.
$.fn.sortTable = function(cls) {
this.find('tr').sort(function(a, b){
return $(a).find('td.'+cls).text() > $(b).find('td.' + cls).text();
}).appendTo(this.find('tbody'));
}
$('table').sortTable('O');
Updated method for supporting ascending and descending orders.
$.fn.sortTable = function (opt) {
var sort = typeof opt.sortType !== 'undefined' ? opt.sortType : 'asc',
cls = opt.cls;
if (!cls) return;
var $tr = this.find('tbody').children().sort(function(a, b){
return $(a).find('.' + cls).text() > $(b).find('.' + cls).text();
});
if (sort === 'des') {
$tr = $tr.toArray().reverse();
}
this.find('tbody').append($tr);
}
$('table').sortTable({
cls: 'N', // className of the cells
sortType: 'des' // order 'asc' || 'des'
});
http://jsfiddle.net/Af7mG/

Adding items to a javascript array

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.

Categories