tommyd456
tommyd456

Reputation: 10683

Unexpected behaviour of FOR loop in Angular app

This is most probably a silly mistake but I can't see the issue. I'm trying to create an array of objects for an image gallery in my Angularjs app. Each photo object has a thumb and img attribute. The for loop is creating the objects fine and I'm logging each to the console to check them:

{thumb: "/10000/0_t.jpg", img: "/10000/0_l.jpg"}
{thumb: "/10000/1_t.jpg", img: "/10000/1_l.jpg"}
{thumb: "/10000/2_t.jpg", img: "/10000/2_l.jpg"}
...

However, after running this code:

var images = [];
var image = {};
for (var i = 0; i < property.images.length; i++) {
    image.thumb = "/" + property.id + "/" + i + "_t.jpg";
    image.img = "/" + property.id + "/" + i + "_l.jpg";
    console.log(image); //this gives expected output
    images.push(image);
};
console.log(images); //this gives all entries as the same

the final console.log gives me:

{thumb: "/10000/27_t.jpg", img: "/10000/27_l.jpg"} //X28

for each image. The 27 comes from the fact that there are 28 images but I can't understand why they all have the same paths?

Upvotes: 1

Views: 94

Answers (3)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48683

Works just fine for me. Please, limit your scope as much as possible in JavaScript.

Refer to chapter 16 Introducing a New Scope via an IIFE in the book; Speaking JavaScript.

Note: An IIFE is an "immediately invoked function expression."

var property = {
  id : 10000,
  images: [{ id: 1 }, { id: 2 }, { id: 3 }]
};

var images = [];

for (var i = 0; i < property.images.length; i++) {
  (function(){
    var image = {}; // This should be inside the loop.
                    // This way the scope does not leak.
    image.thumb = "/" + property.id + "/" + i + "_t.jpg";
    image.img = "/" + property.id + "/" + i + "_l.jpg";
    
    images.push(image);
  }());
};

document.body.innerHTML = '<pre>' + JSON.stringify(images, null, 4) + '</pre>';

Upvotes: 0

Thomas
Thomas

Reputation: 3593

how about this:

var path = "/" + property.id + "/";
var images = property.images.map((img,i)=>{
    return {
        thumb: path + i + "_t.jpg",
        img: path + i + "_l.jpg"
    }
});
console.log(images);

Upvotes: 1

Pointy
Pointy

Reputation: 413826

You need to make a new object on each iteration:

var image;
for (var i = 0; i < property.images.length; i++) {
    image = {};
    image.thumb = "/" + property.id + "/" + i + "_t.jpg";
    image.img = "/" + property.id + "/" + i + "_l.jpg";
    console.log(image); //this gives expected output
    images.push(image);
};

If you don't, then each iteration will re-use that same original object. Passing an object to .push() does not make a copy.

Upvotes: 5

Related Questions