0

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.

3
  • You'll probably want to use array map method, and Promise.all ... and realise you can only return a Promise from loadThumbnail - because asynchrony remains asynchronous Commented Mar 12, 2020 at 0:45
  • it can be an observable too, its works as observable or promise too. do you have any example about your idea? Commented Mar 12, 2020 at 0:47
  • I've added an answer that will work Commented Mar 12, 2020 at 0:50

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

Comments

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.