1

I have difficulties with iterating through array of objects which contains image. As my code below shows the array in console looks kind of empty but when I open it in console, I see all this objects also with iteration numbers. I can't google and get to the point how to transform it into proper working array to make for in loop and iterate through it in Vue.js. I attach you the code where comments says more than my description.

        const frameImage = [
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/lukamodric_165.png'
        },
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/florentinoperez_11.jpg'
        },
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/ramosbarkinsta1.jpg'
        },
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/lukamodric_165.png'
        },
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/florentinoperez_11.jpg'
        },
        {
            url: 'http://www.realmadryt.pl/fotki/_up/newsy/ramosbarkinsta1.jpg'
        },
    ];

    let createdImages = [];

    frameImage.forEach(item => {
        const image = new Image();
        image.src = item.url;
        image.onload = () => {
            // set image only when it is loaded
            createdImages.push({
                image,
                width: image.width,
                height: image.height,
                x: 0,
                y: 0,
                draggable: true
            });
        };
    });
    console.log(createdImages)


    // nothing happens
    createdImages.forEach(item => {
        console.log(item)
    });

    //also nothing happens
    for(img in createdImages) {
        console.log(img);
    }

    //length is actually 0?
    console.log(createdImages.length)

Also jsFiddle: LINK

piotrruss
  • 417
  • 3
  • 11

1 Answers1

1

I would map the array of URLs to an array of promises that resolve with your object when the image has loaded. Then use Promise.all to wait for them all to load (resolve). For example

Promise.all(frameImage.map(({ url }) => new Promise((resolve, reject) => {
  const image = new Image()
  image.onload = () => resolve({
    image,
    width: image.width,
    height: image.height,
    x: 0,
    y: 0,
    draggable: true
  })
  image.onerror = reject
  image.src = src
}))).then(createdImages => {
  // now you can iterate
}).catch(err => {
  console.error('Could not load all images', err)
})
Phil
  • 157,677
  • 23
  • 242
  • 245
  • Unfortunately, I still have problem with returning these createdImages from my method. In a nuthsell createdImages should be returned from outer method which wraps this Promise, how can I achieve that? I know that I have to do it from .then() callback function but I have no idea how – piotrruss Dec 05 '18 at 10:33
  • Oh and I forgot to say that I am using Vue.js and this method is global in "eventBus" state and on my component I use computed property to render these images with v-for. Maybe you know better way to achieve that. – piotrruss Dec 05 '18 at 10:37
  • 1
    Yes, use Vuex. This sort of thing is perfect to put into an asynchronous _action_. See [Returning Promises from Vuex actions](https://stackoverflow.com/q/40165766/283366) – Phil Dec 05 '18 at 10:45
  • Thanks, but it is not that big project and now I achieve what i want by watching computed property which fires when the global images state change and then I push converted state into component own imageArr, is it bad? – piotrruss Dec 05 '18 at 10:47