How do I manipulate objects within arrays? - javascript

I've been given two arrays, each of which has several objects within them. I'm trying to make it so that when a certain dropdown selection is made, it pushes that "flight information" into a "flight summary" div, but I'm having a hard time figuring out how to do it.
var possibleDepartureFlights=[{year:2012,month:11,day:13,hour:17,minute:37,price:137.38} and so on];
var possibleReturnFlights=[{year:2012,month:11,day:18,hour:21,minute:45,price:189.46} and so on];
Each var has 10 objects within the array, each of which has all those properties.
And as a bonus question, I've figured out how to hide a "submit" button when the return flight selected is earlier than the departure, but I can't figure out how to make the submit button come back when a different selection is made!
function displayDivs() {
var departureValue = $('#departureFlightsControl').val();
var returnValue = $('#returnFlightsControl').val();
if (departureValue != "default") {
$('.CumulativeSummary').addClass('totalAvailable');
$('.DepartureSummary').addClass('flightChosen');
}
if (returnValue != "default") {
$('.CumulativeSummary').addClass('totalAvailable');
$('.ReturnSummary').addClass('flightChosen');
}
if ($('#returnFlightsControl').val() < $('#departureFlightsControl').val()) {
$('.SubmitArea').hide();
}
Sorry if this question is vague! I'm new to jQuery and JavaScript, so I'm not really sure what I'm doing (and I'm not even really sure what to Google for to find the answer to my problem(s)). Please use small words, as if you're speaking to a child. Thanks!

Your question is really too broad, anyways... Suppose you have following
var possibleDepartureFlights=[
{year:2012,month:10,day:13,hour:10,minute:37,price:137.38},
{year:2012,month:11,day:15,hour:17,minute:47,price:150.50}
];
The possibleDepartureFlights is an array of two objects and the first element of the array is the first object and it's {year:2012,month:10,day:13,hour:10,minute:37,price:137.38} and it's index is 0 and the second element in your possibleDepartureFlights array is the second object and it's {year:2012,month:11,day:15,hour:17,minute:47,price:150.50} and it's index is 1. Now, if you want to access the month property of the first item of the array then you can write like
alert(possibleDepartureFlights[0].month); // this will alert 10
For the month of the second item/object in the array you can write
alert(possibleDepartureFlights[1].month); // this will alert 11
To loop through the array and print out the each property of every objects, you can try this
for(i=0;i<possibleDepartureFlights.length;i++)
{
console.log(possibleDepartureFlights[i].year);
console.log(possibleDepartureFlights[i].month);
console.log(possibleDepartureFlights[i].hour);
console.log(possibleDepartureFlights[i].minute);
console.log(possibleDepartureFlights[i].price);
}
An Example Here.
Remember, this is only a short example and there are more about arrays and objects in JavaScript. Also remember that you can loop an object with for in like for loop. Also this one could be helpful too.

Related

Use multiple key-value filters on an object of objects?

Bit of a lengthy one so those of you who like a challenge (or I'm simply not knowledgeable enough - hopefully it's an easy solution!) read on!
(skip to the actual question part to skip the explanation and what I've tried)
Problem
I have a site that has a dataset that contains an object with multiple objects inside. Each of those objects contains an array, and within that array there are multiple objects. (yes this is painful but its from an API and I need to use this dataset without changing or modifying it.) I am trying to filter the dataset based of the key-value pairs in the final object. However, I have multiple filters being executed at once.
Example of Path before looping which retrieves the key-value pair needed for one hall.
["Hamilton Hall"]["Hire Options"][2].Commercial
After Looping Path of required key-value pair for all halls, not just one (the hall identifier is stored):
[0]["Hire Options"][2].Commercial
Looping allows me to check each hall for a specific key-value pair (kind of like map or forEach, but for an object).
After getting that out of the way back to the question.
How would I go about filtering which of the looped objects are displayed?
What I have Tried
(userInput is defined elsewhere - this happens on a btn click btw)
let results = Object.keys(halls);
for (key of results) {
let weekend = [halls[ `${key}` ][ 'Hire Options' ][4][ 'Weekend function' ]];
if(userInput == weekend) {
outputAll([halls[ `${key}` ]]);
}
}
That filters it fine. However, I run into an issue here. I want to filter by multiple queries, and naturally adding an AND into the if statement doesn't work. I also dont want to have 10 if statements (I have 10+ filters of various data types I need to sort by).
I have recently heard of ternary operators, but do not know enough about them to know if that is the correct thing to do? If so, how? Also had a brief loook at switches, but doesnt seem to look like what I want (correct me if I am wrong.)
Actual Question minus the babble/explanation
Is there a way for me to dynamically modify an if statements conditions? Such as adding or removing conditions of an if statement? Such as if the filter for 'a' is set to off, remove the AND condition for 'a' in the if statement? This would mean that the results would only filter with the active filters.
Any help, comments or 'why haven't you tried this' remark are greatly appreciated!
Thanks!
Just for extra reference, here is the code for retrieving each of the objects from the first object as it loops through them:
(Looping Code)
halls = data[ 'Halls' ];
let results = Object.keys(halls);
for (key of results) {
let arr = [halls[ `${key}` ]];
outputAll(arr);
}
You can use Array.filter on the keys array - you can structure the logic for a match how you like - just make it return true if a match is found and the element needs to be displayed.
let results = Object.keys(halls);
results.filter(key => {
if (userInput == halls[key]['Hire Options'][4]['Weekend function']) {
return true;
}
if (some other condition you want to match) {
return true;
}
return false;
}).forEach(key => outputAll([halls[key]]));

Is there a way to map a value in an object to the index of an array in javascript?

Prepending that a solution only needs to work in the latest versions of Chrome, Firefox, and Safari as a bonus.
-
I am trying to use an associative array for a large data set with knockout. My first try made it a true associative array:
[1: {Object}, 3: {Object},...,n:{Object}]
but knockout was not happy with looping over that. So I tried a cheating way, hoping that:
[undefined, {Object}, undefined, {Object},...,{Object}]
where the location in the array is the PK ID from the database table. This array is about 3.2k items large, and would be iterated over around every 10 seconds, hence the need for speed. I tried doing this with a splice, e.g.
$.each(data, function (index, item) {
self.myArray.splice(item.PKID, 0, new Object(item));
}
but splice does not create indices, so since my first PKID is 1, it is still inserted at myArray[0] regardless. If my first PK was 500, it would start at 0 still.
My second thought is to initialize the array with var myArray = new Array(maxSize) but that seems heavy handed. I would love to be able to use some sort of map function to do this, but I'm not really sure how to make the key value translate into an index value in javascript.
My third thought was to keep two arrays, one for easy look up and the other to store the actual values. So it combines the first two solutions, almost, by finding the index of the object in the first example and doing a lookup with that in the second example. This seems to be how many people manage associative arrays in knockout, but with the array size and the fact that it's a live updating app with a growing data set seems memory intensive and not easily manageable when new information is added.
Also, maybe I'm hitting the mark wrong here? We're putting these into the DOM via knockout and managing with a library called isotope, and as I mentioned it updates about every 10 seconds. That's why I need the fast look up but knockout doesn't want to play with my hash table attempts.
--
clarity edits:
so on initial load the whole array is loaded up (which is where the new Array(maxLength) would go, then every 10 seconds anything that has changed is loaded back. That is the information I'm trying to quickly update.
--
knockout code:
<!-- ko foreach: {data: myArray(), afterRender: setInitialTileColor } -->
<div class="tile" data-bind="attr: {id: 'tileID' + $data.PKID()}">
<div class="content">
</div>
</div>
<!-- /ko -->
Then on updates the hope is:
$.each(data.Updated, function (index, item) {
var obj = myModel.myArray()[item.PKID];
//do updates here - need to check what kind of change, how long it's been since a change, etc
}
Here is a solution how to populate array items with correct indexes, so it doesn't start from the first one (0 (zero) I meant)
just use in loop
arr[obj.PKID] = obj;
and if your framework is smart (to use forEach but not for) it will start from your index (like 500 in case below)
http://jsfiddle.net/0axo9Lgp/
var data = [], new_data = [];
// Generate sample array of objects with index field
for (var i = 500; i < 3700; i++) {
data.push({
PKID: i,
value: '1'
});
}
data.forEach(function(item) {
new_data[item.PKID] = item;
});
console.log(new_data);
console.log(new_data.length); // 3700 but real length is 3200 other items are undefined
It's not an easy problem to solve. I'm assuming you've tried (or can't try) the obvious stuff like reducing the number of items per page and possibly using a different framework like React or Mithril.
There are a couple of basic optimizations I can suggest.
Don't use the framework's each. It's either slower than or same as the native Array method forEach, either way it's slower than a basic for loop.
Don't loop over the array over and over again looking for every item whose data has been updated. When you send your response of data updates, send along an array of the PKIds of the updated item. Then, do a single loop:
.
var indexes = []
var updated = JSON.parse(response).updated; // example array of updated pkids.
for(var i=0;i<allElements.length;i++){
if(updated.indexOf(allElements[i].pkid)>-1)
indexes.push(i);
}
So, basically the above assumes you have a simple array of objects, where each object has a property called pkid that stores its ID. When you get a response, you loop over this array once, storing the indexes of all items that match a pk-id in the array of updated pk-ids.
Then you only have to loop over the indexes array and use its elements as indexes on the allElements array to apply the direct updates.
If your indexes are integers in a reasonable range, you can just use an array. It does not have to be completely populated, you can use the if binding to filter out unused entries.
Applying updates is just a matter of indexing the array.
http://jsfiddle.net/0axo9Lgp/2/
You may want to consider using the publish-subscribe pattern. Have each item subscribe to its unique ID. When an item needs updating it will get the event and update itself. This library may be helpful for this. It doesn't depend upon browser events, just arrays so it should be fairly fast.

Appending a row to a JavaScript array not working as expected

I have a form that can submit a number of rows of data associated with a given date. One of those fields is a percentage (i.e.: 0-100). I could have three rows of a given date with percentages that add up to 100 (or not, but that's a different validation issue) or two rows with different dates and associated percentages, etc.
I need to keep track of everything and sort all the percentages into the right date buckets on submission so I can do my validation.
To that end, I created an array, PctArray. Each element of PctArray is a two field Object - date, pct. As I loop through submitted data, I check each row's date to see if it's in the PctArray already, and, if so, increment the associated pct field of that date and move on. If not, I create a new element in PctArray and insert the information.
This all works fine and dandy if there's only one row submitted, or even several rows for one date. But the minute I submit information for a second date, it chokes. At this point, I give you the code:
// If this is our first row to process
if(PctArray.length == 0){
PctArray[0] = new Object();
PctArray[0].effdt = datefield.options[datefield.selectedIndex].value;
PctArray[0].pct = parseInt(pctfield.value);
}
else{
// We loop through the array to see if this EffDt exists yet. Not very efficient, but the array will always be small
var found = "no";
for(p=0;p<PctArray.length;p++){
if(PctArray[p].effdt == datefield.options[datefield.selectedIndex].value){
PctArray[p].pct = PctArray[p].pct + parseInt(pctfield.value);
found = "yes";
}
}
if(found == "no"){
PctArray[PctArray.length] = new Object();
PctArray[PctArray.length].effdt = datefield.options[datefield.selectedIndex].value;
PctArray[PctArray.length].pct = pctfield.value;
}
}
The initital take, when it's the first row, everything creates and inserts just fine. But, when I need to go into the block of if(found == "no") it creates the new element, but then dies on the first assignment statement saying Unable to set value of the property 'effdt': object is null or undefined.
I don't get it. I'm declaring the new element the SAME EXACT WAY in both places, but there's something I'm missing that it's not liking about the second time.
I've also tried replacing new Object() with {"effdt":'', "pct":''} with identical results. It works on the top one, not the bottom one.
I'm lost. Does anyone see what I'm missing here?
Thanks.
PctArray[PctArray.length] = new Object();
PctArray[PctArray.length].effdt = datefield.options[datefield.selectedIndex].value;
After the first assignment PctArray.length has increased so you are trying to address non-existing element. You may improve the code by combining your assignments without expllicit new Object():
PctArray.push(
{ effdt: datefield.options[datefield.selectedIndex].value
, pct: pctfield.value
})

Detecting if array object is "in use"

I have some script that is calling AJAX information from a server and then displaying the information into blocks on the page. And every 8 seconds those blocks will fade to a new set of information.
The information from the server is stored in a fixed queue that pushes new items to it every 8 seconds.
And for each block I have it grab a random item from that array to show. The only thing is my blocks are getting a lot of duplicates.
Is there a way to check and see if that array item has been called from another block, and if so it will move on to find another item not in use.
var queue = FixedQueue( 50 );
$(document).ready(function() {
$('.submit').click(function(){
setInterval(function(){
queue.push(fulltweet);
},8000);
});
});
setInterval(function(){
randotime = intervals[Math.floor(Math.random()*intervals.length)];
$('.block1', '.photo1:nth-child(1)').queue(function(){
$(this).hide();
$(this).html(queue[0]);
$(this).fadeIn(2000);
$(this).delay(randotime);
$(this).dequeue();
});
$('.block1', '.photo1:nth-child(1)').fadeOut(2000);
},randotime);
I was creating a random number based on the length of the queue and using that to call queue[rando] but again, I keep getting duplicates in the blocks.
First, if you don't want duplicate items in your array, don't let them to be duplicate. Before inserting new items to your array, control whether it exists in your array or not. Using equality operation may not work if you use objects instead of primitive types(string, integer, etc..). Therefore you need a function checks if a given element exists in the array before insertion, and this function must use a equals function which compares two given objects.
Secondly, javascript allows you to add fields to objects in runtime. So when a block reaches and displays an object, you can put a field over this object. Let's say its name is 'inuse'.
When block A reaches the object:
object.inuse = true;
When block B reaches the same object randomly:
var object = pickRandomly();
while (object.inuse) {
object = pickRandomly();
}
// here's the unique object which is not used by another block.
I hope that helps.
If you can provide a sample code, I can provide a better answer.

Javascript/jQuery Id check to drive numbering function with validation

I need help with a loop... it's probably simple but I'm having difficulty coding it up.
Basically, I need to check existing Ids for their number so I can create a unique id with a different number. They're named like this: id="poly'+i'" in sequence with my function where i is equal to the number of existing elements. Example: Array 1, Array 2, Array 3 corresponding with i=1 for the creation of Array 1, i=2 for Array 2, etc.
Right now i is based on the total number of existing elements, and my "CreateNew" function is driven off x=i+1 (so the example above, the new element will be named Array 4). The problem is that if you delete one of the middle numbers, the "Create" function will duplicate the high number. i.e. Array 1, 2, 3 delete 2, create new-> Array 1, 3, 3.
I need an if() statement to check if the array already exists then a for() loop to cycle through all i's until it validates. Not sure how to code this up.
The code I'm trying to correct is below (note I did not write this originally, I'm simply trying to correct it with my minimal JS skills):
function NewPanel() {
var i = numberOfPanels.toString();
var x = (parseInt(i)+1).toString();
$('#items').append('<div onclick="polygonNameSelected(event)" class="polygonName" id="poly'+i+'"> Array '+ x +' </div>');
$('div[id*=poly]').removeClass('selected');
$('#poly'+i).addClass('selected');
$('#poly'+i).click(function() {
selectedPolygon = i;
$('div[id*=poly]').removeClass('selected');
$(this).addClass('selected');
});
}
THANK YOU! :)
Please clarify "The problem is that if you delete one of the middle numbers, ". What do you mean by delete? Anyway, the simplest solution is to create two arrays. Both arrays will have the same created id's. Whenever an id is created in the first array, an id will be added to the second array. So when it is deleted from first array, check your second array's highest value and then create this id in first array. I hope this did not confuse you.
Well it is hard to tell why you cannot just splice the array down. It seems to me there is a lot of extra logic involved in the tracking of element numbers. In other words, aside from the index being the same, the ids become the same as well as other attributes due to the overlapping 1, 3, 3 (from the example). If this is not the case then my assumption is incorrect.
Based on that assumption, when I encounter a situation where I want to ensure that the index created will always be an appending one, I usually take the same approach as I would with a database primary key. I set up a field:
var primaryKeyAutoInc = 0;
And every time I "create" or add an element to the data store (in this case an array) I copy the current value of the key as it's index and then increment the primaryKeyAutoInc value. This allows for the guaranteed unique indexing which I am assuming you are going for. Moreover, not only will deletes not affect future data creation, the saved key index can be used as an accessor.

Categories