1

I have a grid of pictures on a page. And, periodically, I want to randomly swap one out for one of 50 I have in an array of Objects- but only if they're not already in the grid. This last part is what my code is failing to do.

I first get all 50 items, and put them into an allmedia array:

// initialize
var allmedia = getAllMedia();
var imagesInGrid = [];

When I place the items in the grid, I add to an array of grid items:

imagesInGrid.push(allmedia [i]); // while looping to fill DOM grid

Then, every 8 seconds I run a getRandomImage() routine that randomly gets an image from the allmedia array and then tests it to see if it's not already in the DOM.

function getRandomImageNotInGrid(){
    var randomNumber = Math.floor(Math.random() * allmedia.length);
    if (!isInArray(allmedia[randomNumber], imagesInGrid)) {
        return allmedia[randomNumber];
    } else {
        return getRandomImageNotInGrid();
    }
}

function isInArray(item, arr) {
    if(arr[0]===undefined) return false;
    for (var i=arr.length;i--;) {
        if (arr[i]===item) {
            return true;
        }
    }
    return false;
}

But when I step through the code the (arr[i]===item) test is failing. I can see that the two objects are exactly the same, but the === isn't seeing this as true.

Is this a ByReference / ByValue issue? What am I doing wrong?

console.log:

arr[i]===item
false
arr[i]==item
false
typeof item
"object"
typeof arr[i]
"object"

Edit::

In the output below, I don't understand why arr[0] is not the same as 'item'. I use the exact same object that I put into allmedia as I do when I place the item into the page and, accordingly update imagesInGrid.

console.dir(arr[0]);
    Object
        caption: Object
        comments: Object
        created_time: "1305132396"
        filter: "Poprocket"
        id: "69204668"
        images: Object
        likes: Object
        link: "http://instagr.am/p/EH_q8/"
        location: Object
        tags: Array[2]
        type: "image"
        user: Object
        __proto__: Object

console.dir(item);
    Object
        caption: Object
        comments: Object
        created_time: "1305132396"
        filter: "Poprocket"
        id: "69204668"
        images: Object
        likes: Object
        link: "http://instagr.am/p/EH_q8/"
        location: Object
        tags: Array[2]
        type: "image"
        user: Object
        __proto__: Object
1
  • 2
    Just cause thei're the same image url, doesn't mean it's the same object. Remember, one difference is that one of them is in the grid (on the html-dom), while the other one is not. Rather than check that the objects are the same, check that the img-src is equal. Commented May 18, 2011 at 22:37

3 Answers 3

2

Instead of randomly selecting one from allmedia, can you instead remove one from allmedia?

var randomNumber = Math.floor(Math.random() * allmedia.length);
imagesInGrid.push(allmedia.splice(randomNumber,1));
Sign up to request clarification or add additional context in comments.

4 Comments

well, the issue is that I only show 18 images, but I want to swap out with a bank of 50. I guess I could clone the array of 50 and them splice them out and then when the allmedia is down to 0, rebuild it from the clone.
If I understand you correctly, allmedia has 50 items and imagesInGrid is limited to 18 items. If that's correct then when imagesInGrid gets to a length of 19 just shift out the first element of imagesInGrid and push it onto allMedia: if(imagesInGrid.length=19) allmedia.push(imagesInGrid.shift());
hmmm, I do like this approach, but I still would like to know why my comparison failed.
An object is only ever equal to itself. Here's a simple test: alert({}=={}); A comparison can be made using the object's string values: alert({}.toString()=={}.toString()) but I wouldn't want to rely on that myself... to truly compare two objects, you would need to loop through and test each property: function compareObjs(o,p){for(var i in o)if(!(i in p)||o[i]!=p[i])return false;for(i in p)if(!(i in o))return false;return true;}. If the object you're testing could contain other objects then you'd need to modify that code to check for objects and recursively run compareObjs.
0

When you use ===, you are comparing the objects by reference. What type of objects are you using to compare? Are you sure they are the same object reference? For example, if you are using strings, you may want to use == instead of ===. If you are using DOM objects, you will want to compare the source, as Alxandr suggested.

Also, your for loop syntax appears to be wrong:

for (var i=arr.length;i--;)

Should be:

for (var i=arr.length - 1; i >= 0; i--)

...if I'm not mistaken.

1 Comment

mine is just a short-hand way of doing a loop. It's faster to count down and you don't need that last argument, if the second one is an action.
0

You don't show any code for how the image "objects" are created or how they are added and removed from the DOM. If you are creating image elements and storing references in an array, then replacing the DOM element with the one from the array, then the comparision should work.

However, if your image object is a bundle of data that is used to create an image element for display, then they will never be equal to each other. Every javascript object is unique, it will only ever be equal to itself.

But I suspect the simplest solution is that suggested by ic3b3rg - remove the object from allMedia when you select it, that way you don't have to test if it's already in imagesInGrid because you can only select each image once. If you want the display to go on forever, then when allmedia is empty, put all the images from imagesInGrid back into it and start again.

Edit

Your problem is the for loop. When you set :

for (var i=arr.length;i--;) {
  // On first iteration, i=arr.length
  // so arr[i] is undefined
}

i is not decremented until after the first loop, so set i=arr.length-1. It is more common to use while with a decrementing counter:

var i = arr.length;
while (i--) {
  // i is decremented after the test
}

4 Comments

yeah, i know, but the objects are rather large objects from the Instagram api. I can edit the question above to show the object. But I'm not comparing an array of objects with DOM objects. They are each true arrays of objects. I just mentioned the DOM to inform as to what I was doing with them.
So allmedia is an array of references to Instagram objects? Then when you select one, you push that reference into imagesInGrid? In that case, the two should reference the same object.
yes, exactly. But they're not, for some frustrating reason... grrr.
As for the for loop, i does decrement as soon as you enter the loop. I'm looking at it right now. As soon as it steps in the first time i!==18. Rather, i===17. This is because before the loop is entered, it runs the test to see if it can enter the loop (the second argument is this test). Well, that second argument is "i--", so i is decremented. (i got this loop structure from the book JavaScript Patterns by By Stoyan Stefanov.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.