return objectArray after forEach finish es6+ angular

38 views Asked by At

i have a requeriment where i need to call a rest api with videos links like 'https://videoapi.com/api/video.mp4' and then create a thumbnail for each video object, i've done most of the work, but i'm having problems when i try to return an a new array of objects with the thumbnail i've created before, the process is like this:

  1. Fetch the api array object data

  2. for each element in the array object create the thumbnail with createThumbnail() function i have, this function return a base64 url String.

  3. in the loop i'm creating a new object using the api object propieties and new propiety call videoThumbnail pushing the base64 string i get from the above function.
  4. i need to push every single new object who has the thumbnail url in a new array object and return when it finish.
  5. use the new array object for whatever.

i'm doing good till the part 4, i can create and populate the new object but i dont know how to make the function wait till the loop finish , and if i try to return the new object i get an empty array.

loadThumbnail(list: any){
  let objArrayTemp = [];
  let objTemp = {};
  list.forEach((element,i) => {
  // here i'm creating the base64 strings
  this.createThumbnail(element.videoSrc).then(dataUrl => {
  // here i'm creating the new object for every element in the list
      objTemp = { ...element, videoThumbnail: dataUrl};
      // i want to push every element here
       objArrayTemp.push(objTemp)
     });
  });
 //i want to return the object when the loop finishes the populating process
  return objArrayTemp;
}
console.log(this.loadThumbnail(list)) // this return --- > []

this is my createThumbnail() function

async createThumbnail(thumbnail): Promise<any> {
  return new Promise(resolve => {
    let src = thumbnail; 
    let video = document.createElement('video');

    video.src = src;

    video.width = 360;
    video.height = 240;

    let canvas = document.createElement('canvas');
    canvas.width = 360; 
    canvas.height = 240;
    let context = canvas.getContext('2d');

    video.addEventListener('loadeddata', function() {
      context.drawImage(video, 0, 0, canvas.width, canvas.height);
      let dataURI = canvas.toDataURL('image/jpeg');
     resolve(dataURI)
    });
 })
}

this is the stackblitz with the full recreated code: https://stackblitz.com/edit/angular-hhquzg.

thanks for the help.

1

There are 1 answers

0
Jaromanda X On BEST ANSWER

change loadThumbnail as follows

loadThumbnail(list: any) {
    let objArrayTemp = [];
    let objTemp = {};
    return Promise.all(list.map((element, i) =>  
        this.createThumbnail(element.videoSrc)
        .then(dataUrl => ({...element, videoThumbnail: dataUrl}))
    ));
}

Note: loadThumbnails necessarily returns a Promise, because asynchrony

So to "use" it, it's something like:

this.loadThumbnail(list).then(console.log)

Also, you can remove the async in

async createThumbnail(thumbnail): Promise<any> {

since you never use await, and return a Promise anyway