1

I'm dynamically adding content to HTML where there are images. By design I don't know the actual image data on the time of adding the content, but I'm retrieving this data using JS. I need an event that triggers the function that retrieves this content. So far I've implemented this using a hack:

<img src="_" onerror="loadImage(this)" data-id="1"/>
<img src="_" onerror="loadImage(this)" data-id="2"/>
<img src="_" onerror="loadImage(this)" data-id="3"/>

Each image fails to load src="_" attribute and triggers the onerror handle.

My question is how to avoid triggering the onerror event and call the loadImage by a more appropriate event. I'm looking for an event of each individual img.

Update: don't consider that as an easy question. The images are added dynamically from C++ code into QWebView. There are no actual images that I can access using any URL, but I'm retrieving them as byte arrays from the database (from C++ code as well). I'm accessing the C++ code from the JS function loadImage. I cannot use the window.onload cause the image is added at random moments of time when the main page is already loaded.

Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40
  • Please check this https://stackoverflow.com/questions/263359/how-can-i-determine-if-an-image-has-loaded-using-javascript-jquery – Asutosh Jul 31 '20 at 04:19
  • That link doesn't answer my question. – Dmitry Kuzminov Jul 31 '20 at 04:25
  • Why would you need an event? The code responsible of adding these elements to the DOM certainly can also execute `loadImage` at the same time. Ask the ones that know about QWebView how to do this rather than searching for hacks. – Kaiido Jul 31 '20 at 05:13
  • @Kaiido, I'm trying to **avoid** hacks and that is why I'm asking about HTML/JS but not about QWebView. For sure I can call the functions from C++ code, but that would be a hack if the element can call the function itself. Moreover, in my case I even don't need ids assigned for each image. – Dmitry Kuzminov Jul 31 '20 at 05:18
  • 1
    There is a way to detect additions to the DOM, it's called a [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). – Touffy Jul 31 '20 at 05:18
  • 1
    No, handling it from HTML is definitely the hack. If you have control over what's doing the insertion, that's where you should react to that insertion too, don't ask something unrelated to do it for you. – Kaiido Jul 31 '20 at 05:20
  • However, it sounds like you could do this more efficiently by having your C++ code trigger a JavaScript callback, rather than add an to the DOM directly. – Touffy Jul 31 '20 at 05:20
  • Aside from all that, if you have an ArrayBuffer then it's a simple step to having a URL: `URL.createObjectURL(new Blob(arrayBuffer))` – Touffy Jul 31 '20 at 05:22
  • More efficient would be to avoid HTML at all and develop the whole GUI in C++. The approach I'm using is as efficient as triggering the function from C++ code, but it has benefits from design point of view. Anyway, my question was quitre narrow: how to trigger the event from the itself. – Dmitry Kuzminov Jul 31 '20 at 05:25
  • @Touffy, that is what I'm doing in the `loadImage` function, but it calls a C++ function that has the access to the database. – Dmitry Kuzminov Jul 31 '20 at 05:26
  • You may consider that the element `` is stored in another database as text, the C++ code adds this blindly without knowing what this text contains, and only the JS code figures out that the byte array is needed. – Dmitry Kuzminov Jul 31 '20 at 05:29
  • You could use a ServiceWorker to intercept the fetching of the image source (provided that the `src` is some identifier you can use, not "_"), and respond with a call to your C++ process. – Touffy Jul 31 '20 at 06:47

3 Answers3

0

You can store your image files into an array (list). This code is just an example, this will change the image.src each two seconds, you can handle this with a function as you want.

var list = [
  "image1.jpg",
  "image2.jpg",
  "image3.jpg",
];

var i = 0;
function changeImgs() {
  i++;
  i == list.length ? i = 0 : 0;
  var image = document.getElementById('image');
  image.src = list[i];
  document.getElementById('imgLink').href = list[i];
}

setInterval(function() {
  changeImgs()
}, 2000);

window.onload = changeImgs;

<a id="imgLink" href=""><img id="image"></a>
sonEtLumiere
  • 4,461
  • 3
  • 8
  • 35
  • I need an individual event one per each image. I consider `setInterval` as even dirtier hack than the one with `onerror`. – Dmitry Kuzminov Jul 31 '20 at 04:23
  • you need to get each image element by id, and then apply a function – sonEtLumiere Jul 31 '20 at 04:24
  • Next, I cannot use the `onload` event of the window as I'm adding the content dynamically. – Dmitry Kuzminov Jul 31 '20 at 04:26
  • Image has also events such as `load`, `loadstart`, `loadend`, and you are adding the `src` to `_` so definitely it will give you an error. – Ace Jul 31 '20 at 04:32
  • Instead you can put some dummy image like `This image is loading`, or a animation kind of `gif` and when the javascript wil load the image you can replace the `src` of the image – Ace Jul 31 '20 at 04:34
  • @blacksheep neither one event out of `load`, `loadstart` or `loadend` is triggered. Dummy image is not better than `onerror`. – Dmitry Kuzminov Jul 31 '20 at 04:38
0

Load a placeholder image and then hook into the onload event.

<img src="placeholder.jpg" onload="loadImage(this)" data-id="1"/>
<img src="placeholder.jpg" onload="loadImage(this)" data-id="2"/>
<img src="placeholder.jpg" onload="loadImage(this)" data-id="3"/>
cam
  • 3,179
  • 1
  • 12
  • 15
  • Using placeholder is not better (or even worse) than triggering an error. The second method doesn't answer my question at all, because I'm asking how to trigger the function. – Dmitry Kuzminov Jul 31 '20 at 05:01
  • Placeholder images are common for lazy-loading purposes and make sense when the actual source of the image isn't ready yet. It sounds like the C++ code is inserting the image element into the page but doesnt know what the `src` should be, is this correct? In this case then a placeholder image + `onload` makes sense. – cam Jul 31 '20 at 05:11
  • There are no URLs at all. I store images in the database and retrieve the actual byte data, so the `src` attribute is useless. More or les the lazy loading is what I've implemented using `onerror` event, but in my case I don't have to store a placeholder as a file. Due to the fact that WebKit is synchronous, the placeholder is even not needed. – Dmitry Kuzminov Jul 31 '20 at 05:15
0

You mentioned that the image src is a byte array that the c++ code has access to, you can use a byte array directly in the img src as follows:

<img src="data:image/jpg;base64, [byte array]">
cam
  • 3,179
  • 1
  • 12
  • 15
  • That is a good advice, but let's consider that I wish to separate adding the image and retrieving the byte array into different modules. PS I wonder who and why downvoted your answer... – Dmitry Kuzminov Jul 31 '20 at 05:21