Sometimes, .splice is not a function - javascript

I am stuck with a weird error. I get .splice is not a function in the console, but in fact, I am doing .splice on a array (which is valid). Moreover, it don't get always the error. When I refresh the page, sometimes I get it and other times, I don't get it. I don't understand why. Could you explain me my mistake, what am I doing wrong here?
EDIT : I forget to mention that between my declaration of variable array (var ... = []) and my jQuery.getJSON, I am adding stuff inside my variable (integers). That is why I am using splice. I want to order well my array with my new items from the JSON. Also, all arrays contain the same amount of elements. I am always adding the same quantity of elements in each array.
Here is my problematic code :
var HeightLegs = [];
var IdLegs = [];
var PriceLegs = [];
var QuantityLegs = [];
jQuery.getJSON('/products/legs.js', function (product)
{
for (var i = 0; i < product.variants.length; i++)
{
var indexToAdd = 0;
while (indexToAdd < HeightLegs.length && HeightLegs[indexToAdd] < +(product.variants[i].option1.replace('"', '')))
{
indexToAdd++;
}
IdLegs.splice(indexToAdd, 0, product.variants[i].id);
HeightLegs.splice(indexToAdd, 0, +(product.variants[i].option1.replace('"', '')));
PriceLegs.splice(indexToAdd, 0, product.variants[i].price / 100);
if (product.variants[i].inventory_policy == "continue")
QuantityLegs.splice(indexToAdd, 0, 1);
else {
// MY ERROR IN THE CONSOLE IS ON THIS SPLICE ONLY!!!!
QuantityLegs.splice(indexToAdd, 0, product.variants[i].inventory_quantity);
}
}
});
What I don't understand is that the error is not constant. Sometimes I get it and other times I won't...
Thanks for the help!

According to comments above:
Errors like what.ever is not a function means that what is defined, but method ever is not bound to this object. It causes only two things (if I know):
a) misspelled name of method (ever)
b) wrong type of object/class (what)
In this case, error occured because var ShopifyQuantityLegs was accidentally set to Number (ShopifyQuantityLegs=1) so b) is the clue

Related

Javascript TypeError: Cannot read property 'indexOf' of undefined

In this code I want to remove an element from the cart_products array.
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
$.each(cart_products,function(key, item) {
if(item.indexOf(product+"^") !== -1){
cart_products.splice(key, 1);
}
});
But I get this error in Google Chrome console:
Uncaught TypeError: Cannot read property 'indexOf' of undefined
Is there something wrong with the code?
Thanks for your help.
The problem is that you're modifying the array while jQuery's $.each is looping over it, so by the time it gets to the end, the entry that used to be at index 2 is no longer there. (I admit I'm a bit surprised $.each behaves that way, but I haven't used $.each in at least five years, so...)
If the goal is to remove matches from the array, the better choice is filter:
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
cart_products = cart_products.filter(function(item) {
return item.indexOf(product+"^") === -1;
});
console.log(cart_products);
...or alternately if it's important to modify the array in-place rather than creating a new one use a boring for loop as Andreas points out looping backward through the array so it doesn't matter when you remove things:
var cart_products = ["17^1", "19^1", "18^1"];
var product = 17;
var target = product + "^";
for (var index = cart_products.length - 1; index >= 0; --index) {
if (cart_products[index].indexOf(target) !== -1) {
cart_products.splice(index, 1);
}
}
console.log(cart_products);
First of all, you don't need to use a jQuery each for this. Second, it's not a great idea to alter an array that you are operating on. If you're trying to remove elements from an array, use filter. Filter has the following signature:
someArray.filter(function(item, index, array) {
// return a value that is truthy to keep an item or falsey to remove it
})
Filter returns a new array with only the values that match what you want. That means you don't mess with your original array, which is a good idea anyways. In your case it would look like this:
var filteredProducst = cart_products.filter(function(item) {
return item.indexOf(product + "^")
})

jQuery - using global array and wait for $get to load retrieved data?

Been struggling all day with looking at code examples and can't get this to work.
Basically I want to load an array using the HTML from four local files.
Then I'll use that HTML to fill a div dynamically with some kind of animated slider.
My problem is that I can't seem to get the timer to wait for the html to be retrieved and assigned to the variables. The GET is working great, but the variables don't seem to be loaded outside the GET loop.
I can see the asynch GET filling the array properly, but the elements remain undefined in the loop. I think they're global variables so it shouldn't be that.
I'm new at jQuery and have been using SO for examples, so open to any suggestions - hopefully this is just an obvious fix for an experienced javascript coder.
Here's my code:
window.standings = new Array(4);
window.iURL = 0;
standingsURL = ["MondayNight.html", "TuesdayNight.html", "WednesdayNight.html", "ThursdayNight.html"]
for (window.iURL = 0; window.iURL < window.standings.length; window.iURL ++) {
$.get(standingsURL[window.iURL], function( data ) {
window.standings[window.iURL] = data;
alert (window.standings[window.iURL]);
}, "text");
}
setTimeout(function repeatTimeout() {
if(window.standings[window.standings.length] !== undefined){
for (window.iURL = 0; window.iURL < window.standings.length; window.iURL ++) {
alert (window.standings[window.iURL]);
}
} else {
alert ("Wait again");
setTimeout(repeatTimeout, 2500);
}
}, 1000);
The first issue I can see is that in your repeatTimeout function, you're referencing an item in your array that doesn't exist.
window.standings[window.standings.length]
which is equivalent to window.standings[4]
You have an array with four items in it, and you're referencing array index 4 here - but arrays are zero-indexed, so only indexes 0, 1, 2, and 3 are valid. Try:
window.standings[window.standings.length - 1]
Edit:
Declare an empty array:
window.standings = []
Instead of: window.standings[window.iURL] = data;, do this:
window.standings.push(data)
Your if function now checks for length:
if(window.standings.length === 4)
This is a relatively crude solution. Check out this SO post for more information about the when function.

array undefined after pushing to object

I'm pushing an object into an array of objects. One of the properties of the object (which is an array) is showing up as undefined, after the object is pushed to the array. If you look at my code below, where it says, "WHY IS THIS SHOWING IN CONSOLE?" - it doesn't make sense because if the array is undefined, it should have been undefined in both of the previous two checks (where it says "THIS IS NOT SHOWING IN CONSOLE."). This is driving me crazy. SOS. Please help.
var pathCopy = unit.path; // THIS IS AN ARRAY AND IT IS NOT EMPY
var directionCopy = unit.direction;
if (pathCopy.length < 1) {
console.log('THIS IS NOT SHOWING IN CONSOLE');
}
var object = {
'type': 'move',
'time': gameTime,
'name': unit.name,
'vector': pathCopy,
'direction': directionCopy
};
currentGameEvents.push(object);
if (object.vector.length < 1) {
console.log('THIS IS NOT SHOWING IN CONSOLE');
}
for (var i = 0; i < currentGameEvents.length; i++) {
if (currentGameEvents[i].vector.length < 1) {
console.log('WHY IS THIS SHOWING IN CONSOLE??');
}
}
I’m not sure how or why, but your example works, if I insert the undefined variables (i.e. I replaced unit.path with [345,34623,52] or something that is an array literal).
The only difference to that is, that you actually assign the reference to that array, instead of declaring a new array.
var pathCopy = unit.path; // pathCopy and unit.path are the SAME array
var pathCopy = [345,346,345]; // pathCopy is a completely NEW array
To fix this, try something like
var pathCopy = unit.path.slice(); // pathCopy is a completely NEW array that contains the same values as unit.path
whenever you want to copy an array; add .slice() at the end!
Again, this is deducing from the only difference between your code and what I tried, and this is probably the reason, why your code doesn’t work.
Another assumption is that currentGameEvents is an Array. Your code wouldn’t work at all, otherwise. I’m mentioning this because the title states that you were trying to push to an object, which isn’t possible.

Uncaught TypeError: Cannot read property - Though property exists

var sorted = DocumentListData.Documents.sort(function (a, b) {
var nameA = a.Document.toLowerCase(),
nameB = b.Document.toLowerCase();
return nameA.localeCompare(nameB);
});
for (var i = 0, len = sorted.length; i < len; i++) {
if (sorted[i].Document=== 'abc') {
sorted.splice(i, 1);
}
if (sorted[i].Document=== 'xyz') {
sorted.splice(i, 1);
}
}
I am just breaking my head for one hour on what is the mistake going here. It throws me Document is undefined, though the Document property exists.
Uncaught TypeError: Cannot read property 'Document' of undefined. When i remove the sorted.splice(i,1), it works and there is no error.
You're modifying an array that you're iterating over. splice(i,1) removes the ith element. When you splice the sorted array you're removing elements, so you eventually go past the length of the array, since the loop goes to the original length of the array. sorted[i] is then undefined, and you get the error you're describing.
Generally its never a good idea to modify an array that you're currently iterating over in that fashion. If you have to do it that way make sure to include if checks to see that i is not >= to the current length of the array. But using a while loop is probably a better fit here.
var counter =0;
while(counter < sorted.length) {
var doc = sorted[counter].Document;
if (doc === 'abc' ||doc === 'xyz') {
sorted.splice(counter, 1);
}
else{
counter++;
}
}
A few more thoughts
document is a predefined variable in the browser environment for javascript, and generally JS has a convention that capitalized variables are only for constructor functions. So Document is probably not a great property name choice.
If you don't need to support older versions of IE you can also look into Array.Prototype.filter as a cleaner way of doing what you want
If the Document of the last element is abc, it will be removed in the first if condition.
sorted[i] will the become undefined (as you've removed the last element), and when the 2nd if runs, you'll get the error you're describing.
You'll be able to fix this by using an else if:
if (sorted[i].Document=== 'abc') {
sorted.splice(i, 1);
} else if (sorted[i].Document=== 'xyz') {
sorted.splice(i, 1);
}

Can I select 2nd element of a 2 dimensional array by value of the first element in Javascript?

I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?

Categories