General javascript question re: p5 tutorial

Hi. I’m following a p5.js tutorial and have the below code. Would anyone be able to help me understand how could add a second image to this fetch?
Thanks!

`

        displayMyImg()
            .then(function (response){console.log('done');
            })
            .catch(function (error) {
                console.log('error!');
                console.error(error);
            });
        
        async function displayMyImg() {
            var response = await fetch('myImg.jpg')
            var responseBodyBlob = await response.blob();
            document.getElementById("hand").src=URL.createObjectURL(responseBodyBlob);
        }

`

Hi,

You want to display multiple images with a single function. So what do you use? Parameters are your friends! :wink:

Make an url parameter and use it inside your function :

async function displayMyImg(url) {
  var response = await fetch(url)
  var responseBodyBlob = await response.blob();
  document.getElementById("hand").src=URL.createObjectURL(responseBodyBlob);
}

Then call it multiple times :

displayMyImg("Test.jpg");
displayMyImg("example.png");
...
1 Like

Hi
if your purpose is to get one more picture and display it, you won’t make it in once.
You will need to make a fetch request for each of your images, then add your image at your existing DOM or create a new element to insert it in the source.

As given by @josephh, you will change the source (so the image) of the element owning the id "hand’. You might need to add multiples images, so create a new element in this case :

  async function displayMyImg(url) {
  var response = await fetch(url)
  var responseBodyBlob = await response.blob();
  let myImage = document.createElement('img');
  myImage.classList.add('my_images'); // create a class to style your img (size, position, margin etc)
  document.getElementById("hand").parentElement
                                 .appendChild(myimage); // select the parent of "hand", then add our new image to it
}
2 Likes

Thanks! I understand parameters but I’m still learning, this makes sense.
However, if I wanted to be able to display multiple images at the same time in different divs using your code above, wouldn’t I need to have a second
document.getElementById("hand").src=URL.createObjectURL(responseBodyBlob);
and then also change its ID? That’s part of what I was stuck on. Where does it go?

EDIT: I’m working on Pr0tonX’s response above now.

Thanks for this! I hate to ask but could you dumb it down at all?
I can understand the variables, but not the last line. Don’t I still need to include this somewhere?
document.getElementById("hand").src=URL.createObjectURL(responseBodyBlob);

Hi again,

Yes you are right, @Pr0tonX answer’s code doesn’t use the responseBodyBlob that we just fetch.

If you want to display multiple images in different divs, you can add a second argument to the function specifying the id of that div :

// url -> the url of the image
// containerDivId -> the div that will contain the image
async function displayMyImg(url, containerDivId) {
  var response = await fetch(url)
  var responseBodyBlob = await response.blob();
  document.getElementById(containerDivId).src = URL.createObjectURL(responseBodyBlob);
}
1 Like

Hi,

you’re right, I missed to add it because it was already mentionned by @josephh. When you have created your img element, you have to give it the url, and then add it as a child of a images container, so it would make the following :

  async function displayMyImg(url) {
  var response = await fetch(url)
  var responseBodyBlob = await response.blob();
  let myImage = document.createElement('img'); // create a new element "img", but it is inserted in the page yet
  myImage.classList.add('my_images'); // give it a class to style all the images same
  myImag.src=URL.createObjectURL(responseBodyBlob); // set the url of the image from your fetch request
document.getElementById([id_of_image_container : could be hand]) // select the image container
                                 .appendChild(myimage); // then add our new image to it
}

As you see, I changed my last line for maybe an easier example. This way, we select a parent in which add child elements.

So as given by @josephh, a function taking in parameters the url of the fetch, plus the id of the container is the good way to proceed :

  async function displayMyImg(url, containerID) {
  var response = await fetch(url)
  var responseBodyBlob = await response.blob();
  let myImage = document.createElement('img'); // create a new element "img", but it is inserted in the page yet
  myImage.classList.add('my_images'); // give it a class to style all the images same
  myImag.src=URL.createObjectURL(responseBodyBlob); // set the url of the image from your fetch request
  document.getElementById(containerID) // select the image container
                                 .appendChild(myimage); // then add our new image to it
}
3 Likes

Ok first off thank you both so much for the help. This is by far the best forum for learning coding.

So I’ve taken what you wrote and I’ve been trying to troubleshoot it but nothing works for me. (Also your version makes more sense than what I have regarding the img element, whereas mine shows an empty image on the page yours suggests not displaying the img element until the source is set, I just wasn’t sure how that’s supposed to work.)

Here’s what I have, any ideas what the problem could be? It console logs this error:

TypeError: Cannot read property ‘appendChild’ of null
at displayMyImg (displayImgs.html:32)

        <div id="myDiv1">
            <img src="" id="myImg" width="50%"/> 
            <button onclick=displayMyImg("img1.jpg", "myDiv1")>click me</button>
            <button onclick=displayMyImg("img2.jpg")>click meee</button>
        </div>

        <script>
            
            displayMyImg() //invoke the function
                .then(function (response){console.log('done'); //then it fetches the url from the ?
                })
                .catch(function (error) {
                    console.log('error!');
                    console.error(error);
                });
            
            async function displayMyImg(url, containerID) { //p5 forum version
                  var response = await fetch(url)
                  var responseBodyBlob = await response.blob();
                  
                  let myImage = document.createElement('img'); // create a new element "img", but it is not inserted in the page yet
                  myImage.classList.add('my_images_css'); // give it a class to style all the images same
                  myImage.src=URL.createObjectURL(responseBodyBlob); // set the url of the image from your fetch request
                  document.getElementById(containerID).appendChild(myImage); // select the image container and then add our new image to it
                                                  
            }
</script>

Hi,

Happy that it’s helping you!

The error is coming from the line where you invoke the displayMyImg() function.

Since we modified this function to accept two arguments, you need to give some. In JavaScript, there’s no error when you call a function with a different number of arguments. If you don’t specify them, they are going to hold the undefined value by default.

Therefore, containerId is undefined so document.getElementById(containerID) returns null so it pops an error because you can’t add a dom element to null.

As we said earlier, you need to call the function with the url of the image and the container id.

Like this :

displayImg("myImage.png", "divID").then(...)...
3 Likes

Hi,

actually you “invoke” three times your function displayMyImg :

  • once each time we click on one of your buttons
  • once in your script : you call your function at the beginning of your script ( displayMyImg().then() etc ).

In both case there is some issues :

  • for the buttons :
    the first button is right, you gave in arguments the url of the img and the container id
    the second one isn’t because you didn’t give the containerID while it is needed in your function

  • for the script :
    you defined your function with the following

async function dispayMyImg(url, containerID){ 
//code 
} 

but when you write

displayMyImg().then() //etc

you actually call your function, without any arguments.

Then, there is two possibilities of how you can do it :

  • either you choose to change the url of your already existing <img> tag you put in your html code, and so only one image is displaying at the same time
  • either you choose to add one img element for each new image, so you will create mutiples image elements ; actually one each time you call your function

From what I can see from your code, it seems that you want the first option : changing the url of the image tag ; then you won’t need to create element as I proposed but just replace the url of the image element as explained in the @josephh 's post.

And finally, if you want to display by default an image, you need to call the displayMyImg function in your script indeed, but with arguments. If you don’t want to display an image before clicking, you can remove it.

2 Likes

Alright it’s working! That probably took me longer than expected but I’ve been working on it, I was still a little confused (also made some obvious errors above when I knew better).
Thanks for all the help! I have so many more questions now :wink:
Best coding forum/community.

2 Likes