The image already in the document object model (DOM) will now display a spinner when a new image is introduced

I have created a basic app that displays images and allows users to add more. When adding an image, I show a spinner while it loads and hide the spinner once the loading is complete. However, I encountered a problem where the spinner does not appear when adding a second image. This issue seems to be caused by the boolean variable I am using, which appears to be used globally.

It's important to note that I add images using their URL and render them with the HTML img tag. My app utilizes RactiveJS, and I believe there might be a solution involving a unique identifier, although I'm unsure of how to implement it. Each image has a unique ID assigned to its data.

Below is the snippet of Ractive code:

let isImageLoaded = false;

const ractive = new Ractive({
  el: '#container',
  template: `
    {{#each images}}
      <div class="container">
        {{#if !isImageLoaded}}
           <span class="spinner"></span>
        {{/if}}

         <img 
            alt="" 
            src="{{url}}" 
            on-load="imageLoaded"
            style="display: {{isImageLoaded ? 'block' : 'none'}};"
         />
      </div>
    {{/each}}
  `,
  data: {
    images: [
      { id: 1, url: 'https://www.some-image.com/image1.jpg' },
    ],
    isImageLoaded : isImageLoaded
  }
});

ractive.on('imageLoaded', function(e) {
  ractive.set('isImageLoaded', true); 
});


function addImage(image) {
  const allImages = ractive.get('images');

  allImages.push(images);

  ractive.set('isImageLoaded', false); 
  ractive.set('images', allImages);
}

If I set isImageLoaded to false in the addImage function, adding a new image causes all other spinners to appear.

I am seeking advice on how to use IDs to make each image and spinner unique, ensuring the spinner only appears when adding a new image. Any suggestions would be greatly appreciated!

Answer №1

To ensure that each image is tracked individually for loading status, one approach is to transform isImageLoaded into an object where image IDs serve as keys and boolean values indicate the loading status.

let imageLoadStatus = {};

const ractive = new Ractive({
  el: '#container',
  template: `
    {{#each images}}
      <div class="container">
        {{#if !imageLoadStatus[id]}}
           <span class="spinner"></span>
        {{/if}}

         <img 
            alt="" 
            src="{{url}}" 
            on-load="imageLoaded"
            style="display: {{imageLoadStatus[id] ? 'block' : 'none'}};"
         />
      </div>
    {{/each}}
  `,
  data: {
    images: [
      { id: 1, url: 'https://www.some-image.com/image1.jpg' },
    ],
    imageLoadStatus : imageLoadStatus
  }
});

ractive.on('imageLoaded', function(e) {
  ractive.set(`imageLoadStatus[${e.context.id}]`, true); 
});


function addImage(image) {
  const allImages = ractive.get('images');

  allImages.push(images);

  ractive.set('images', allImages);
}

Answer №2

Make sure to include the loaded: false property in each image object

Add a function called imageLoaded after the data section

Update the {{#if}} statement to:

{{#if !.loaded}}
   <span class="spinner"></span>
{{/if}}

Invoke it using

on-load="@this.imageLoaded(@index)"

Use .loaded within the if statement since you are already iterating over each image

The imageLoaded function that comes after the data should look like this:

imageLoaded: function(i){
    this.set('images['+i+'].loaded',true);
  }

In the style section, add the following:

style="display: {{.loaded ? 'block' : 'none'}};"

Keep in mind that loaded is a key within each images item

I also introduced a variable called lastImageID in the data where I store the highest id to easily increment for the next added image.

Furthermore, I implemented an addImage(num) function and everything runs smoothly!

Pro tip: Outside functions can be called with onclick, while Ractive.js functions can be triggered with on-click, as seen in a button example

.spinner {
        background-color:black;
        width: 48px;
        height: 48px;
        border: 5px solid #FFF;
        border-bottom-color: transparent;
        border-radius: 50%;
        display: inline-block;
        box-sizing: border-box;
        animation: rotation 1s linear infinite;
        }
    
        @keyframes rotation {
          0% {
            transform: rotate(0deg);
          }
          100% {
            transform: rotate(360deg);
          }
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/chance/0.5.6/chance.min.js"></script>
    <script src='https://cdn.jsdelivr.net/npm/ractive'></script>



        <div id="target" ></div>
        <script id='template' type='text/ractive'>
        {{#each images}}
              <div >
                {{#if !.loaded}}
                   <span class="spinner"></span>
                {{/if}}
                 <img 
                    alt="" 
                    src="{{url}}" 
                    on-load="@this.imageLoaded(@index)"
                    style="display: {{.loaded ? 'block' : 'none'}};"
                 />
              </div>
            {{/each}}
            <button onclick="addImage(1)">add 1 images</button>
            <button onclick="addImage(2)">add 2 images</button>
            <button onclick="addImage(5)">add 5 images</button>
            <button onclick="addImage(10)">add 10 images</button>
        </script>
        
        <script>
        const ractive = new Ractive({
          el: '#target',
          template: '#template',
          data: {
            images: [
              { id: 1, url: 'https://randomuser.me/api/portraits/med/women/52.jpg',loaded:false },
            ],
          },
          imageLoaded: function(i){
          //simulate that image takes some time to load with setTimeout
          setTimeout(() => { this.set('images['+i+'].loaded',true); }, 1000);
            
          }
        });
        
        
        function addImage(num) {
          for (var i = 1; i<=num; i++) {
                var gender = chance.bool() ? 'men' : 'women';
                ractive.push('images',
              {
                id: [...ractive.get('images')].pop().id+1,
                url: 'https://randomuser.me/api/portraits/med/' + gender + '/' + (chance.natural() % 100) + '.jpg',
                loaded: false
              }
            );
          }
        }
        
       
        </script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Prevent additional functions from running when clicking in Angular 5

I have implemented an Angular material table where each row expands when clicked. In the last cell of the table, I load a component dynamically using ComponentFactory. This loaded component is a dropdown menu. The problem arises when the dropdown menu is ...

Employing the unshift method on a two-dimensional array

I've been experimenting with the unshift function on a multidimensional array, but I'm having trouble getting it to work as expected. Using shift works fine and does what I need, but unshift doesn't behave properly. Here is the array I&apo ...

How can I identify the moment when an AngularJS route controller is no longer in scope?

Currently, I have a controller set up to poll the server at regular intervals using $timeout. The issue arises when the route changes - I need to stop the polling and then restart it once the original route is accessed again. If anyone has any suggestions ...

Launching shuttles using HTML and JavaScript

I've been working on an HTML code with JavaScript for a platform validation project. Over the last couple of weeks, I've been diligently coding and testing to ensure everything runs smoothly. However, my code suddenly stopped responding, leaving ...

How can I detect click events in individual button-like areas on an image sprite using JQM?

When using Jquery Mobile, imagine having 2 button-like elements in an image sprite. These buttons need to be custom buttons within the image sprite: --------- | button1 | --------- | button2 | --------- 1.) How can I detect click events for each butto ...

Determining the exact moment a dynamic component finishes loading

Currently, I am dynamically loading various components in this manner: const Page0 = () => import("@/components/pages/tutorial/Pages/Page0") const Page1 = () => import("@/components/pages/tutorial/Pages/Page1") There are additional pages similar to ...

Passing an array through ajax from PHP to JavaScript using a properly formatted JSON structure

I began with an array generated by PHP and retrieved via ajax, which had the following structure: Array ( [0] => {id:"12",from:"09:00:00",to:"15:00:00"} [1] => {id:"13",from:"08:00:00",to:"10:00:00"} [2] => {id:"12",from:"15:00:00",to ...

Oops! Vue.js router configuration is throwing an error because it's unable to read properties of undefined when trying to access 'use'

Description: I have been working on a leaderboard web application using Vue.js. When I tried to launch the server on localhost after finishing my code, I encountered an error. The error message I received is as follows: Uncaught runtime errors: ERROR Cann ...

ExpressJS exhibits unique behavior based on whether the API is requested with or without the specified PORT number

I have encountered an issue with my 2 flutter web apps. One of them is functioning flawlessly when I request the URL, but the other one only works when I include the port xxxxx:4000/nexus-vote. However, when I remove the port, I receive a status code of 20 ...

"jQuery's .each() method is only iterating through the last element in

I am encountering an issue with this function not operating correctly... only the last Element shows the box. NOTES: <aside> is set to position: fixed; and I understand that this is not the "correct" use of <article> tags, but it helps me dist ...

What is the VueJS 3 alternative to the JS Select() function?

I am having trouble selecting the password textbox in my code when it does not match with the confirm password textbox after clicking the register button. Click here to see the image of the desired output Is there a similar function to select() in VueJS t ...

Instructions for rotating a Vector3 in Three.js along an axis

Is there a way to rotate a Vector3 from Three.js around an axis by a specific angle? I need help with this process. ...

Deleting the HTML element

Can someone assist me with my script issue? I am facing a problem: when I open my file on fullscreen (over 768px), and move my pointer around the logo div, nothing happens. However, if I resize my browser to below 768px, then back again above 768px, the ...

Steps for concealing a specific field in StrongLoop's outcome

Currently, I am working on a project using strongloop to develop a web service for user login. While my code is functioning properly and producing the desired output, the issue lies in the fact that it does not hide the password. The result I am receiving ...

Issues encountered when attempting to make a post login request in AngularJS

I am having trouble requesting login authentication from a URL using payload in AngularJS The code below is functioning properly: $http({ method: 'POST', url: URL + '&user=' + $scope.vModel.username + '&passwor ...

Eliminate the selection in a DropDownListFor when choosing a specific option in a separate dropdown

I'm currently facing a challenge with understanding JavaScript. As a newcomer to this language, I am striving to make it work in the following scenario: When the "Healthcare" option is selected from the "discipline" dropdown menu, the choice for "P ...

Leverage videojs-vr within a Vue.js component

I have been experimenting with integrating the videojs-vr package, which I installed through npm, into a Vue.js component. However, I encountered an error: TypeError: videojs is not a function at VueComponent.mounted (VR.vue?d2da:23) at callHook (vue.esm. ...

I am working with Vue.js 2.0 and attempting to send an event from a `child component`

I've been working with Vue.js 2.0 and I'm facing an issue trying to emit an event from a child component to the parent component, but unfortunately, it's not functioning as expected. Here is a glimpse of my code: child component: <temp ...

When attempting to browse for image files, Postman fails to display images

While trying to upload image files through Postman, I encountered an issue where the browser did not display any image files. It's important to note that I am using Ubuntu as my operating system. https://i.sstatic.net/1D3ro.png When I clicked on "se ...

Refreshing React state

My basic component subscribes to an EventEmitters event to accumulate an array of messages. However, I'm facing an issue where the message array only ends up containing the latest message. Below is the source code for the component: export const Mess ...