Using Alpine JS to rotate through images at regular intervals using the window.setInterval() method

Attempting to tackle a simple task using Alpine JS and the standard JS function setInterval. The goal is to create an image selector where images switch every second (1000ms).

Here's what I have so far:

<div x-data="imgFunc()">
        <h1 class="text-xl py-3">Choosing the picture</h1>

        <div class="w-1/2">
            <img x-show = "img === 'img1'" src="{{ asset('images/training/img1.jpg') }}" alt="Main Image">
            <img x-show = "img === 'img2'" src="{{ asset('images/training/img2.jpg') }}" alt="Main Image">
            <img x-show = "img === 'img3'" src="{{ asset('images/training/img3.jpg') }}" alt="Main Image">
        </div>

        <div>
            <ul class="flex">
                <li class="w-1/6 p-3" :class="{ 'border' : img==='img1' }"><img src=" {{ asset('images/training/img1.jpg') }} " alt="image1" @click = "startImg"></li>
                <li class="w-1/6 p-3" :class="{ 'border' : img==='img2' }"><img src=" {{ asset('images/training/img2.jpg') }} " alt="image2" @click = "img='img2'"></li>
                <li class="w-1/6 p-3" :class="{ 'border' : img==='img3' }"><img src=" {{ asset('images/training/img3.jpg') }} " alt="image3" @click = "img='img3'"></li>
            </ul>
        </div>



    </div>



<script>
    function imgFunc(){
            var i = 1;
            var img ='img'+i;
            return {
            i,
            img,
            startImg(){
                var myvar = window.setInterval(function(){
                    this.img = 'img'+this.i;
                    if(this.i<3){
                        this.i++;
                    }else{
                        this.i=1;
                    }    
                }, 1000);
            },
            changeImg() {
                this.img = 'img'+this.i;
                if(this.i<3){
                    this.i++;
                }else{
                    this.i=1;
                }                       
            }

        }
        
    }

</script>

When clicking on image#1 in the list, the images should begin changing, but it doesn't happen. Why?

I also attempted passing the function name changeImg() in the @click event, and that worked perfectly, with images changing sequentially upon each click.

I also tried passing the function name changeImg() to setInterval() like this:

startImg(){
     var myvar = window.setInterval(this.changeImg, 1000);
},

Or like this:

startImg(){
     var myvar = window.setInterval(changeImg, 1000);
},

I experimented with changing "this" to "self"

<script>
    function imgFunc(){
            var i = 1;
            var img ='img'+i;
            var self=this;
            return {
            i,
            img,
            startImg(){
                var myvar = window.setInterval(function(){
                    self.img = 'img'+self.i;
                    if(self.i<3){
                        self.i++;
                    }else{
                        self.i=1;
                    }    
                }, 1000);
            },
            changeImg() {
                this.img = 'img'+this.i;
                if(this.i<3){
                    this.i++;
                }else{
                    this.i=1;
                }                       
            }

        }
        
    }

</script>

However, nothing seems to work as intended.

Answer №1

The problem you're facing is with the usage of the function, causing the reference of this inside the function to not be referring to the Alpine.js this. Similarly, the this within the imgFunc function is also not pointing to the Alpine.js this. This occurs because imgFunc is executed before Alpine.js initializes, resulting in this referring to the window object.

To resolve this issue, there are two approaches. One option is to utilize this but use an arrow function within the setInterval:

<script>
    function imgFunc(){
            var i = 1;
            var img ='img'+i;
            return {
            i,
            img,
            startImg(){
                var myvar = window.setInterval(() => {
                    this.img = 'img'+this.i;
                    if(this.i<3){
                        this.i++;
                    }else{
                        this.i=1;
                    }    
                }, 1000);
            },
            changeImg() {
                this.img = 'img'+this.i;
                if(this.i<3){
                    this.i++;
                }else{
                    this.i=1;
                }                       
            }

        }
        
    }

</script>

Alternatively, you can assign self = this in the startImg function:

<script>
    function imgFunc(){
            var i = 1;
            var img ='img'+i;
            return {
            i,
            img,
            startImg(){
                var self=this;
                var myvar = window.setInterval(function(){
                    self.img = 'img'+self.i;
                    if(self.i<3){
                        self.i++;
                    }else{
                        self.i=1;
                    }    
                }, 1000);
            },
            changeImg() {
                this.img = 'img'+this.i;
                if(this.i<3){
                    this.i++;
                }else{
                    this.i=1;
                }                       
            }

        }
        
    }

</script>

An alternative method involves using .bind on the setInterval callback, although it may be more elaborate and complex.

Answer №2

Hugo brought up the point that the context of this doesn't refer to the outer function, so arrow functions are needed as they lack a context.

I've made some modifications to utilize alpine.js for its intended purpose.

<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.1/tailwind.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.7.3/alpine.js"></script>
<div x-data="imgFunc()">
  <h1 class="text-xl py-3">Choosing the Picture</h1>

  <div class="w-1/2">
    <img :src="currentImage" alt="Main Image">
  </div>

  <div>
    <ul class="flex">
      <template x-for='(image,index) in images'>
        <li class="w-1/6 p-3" :class="{'border': currentImage===image}">
          <img :src="image" alt="Image1" @click="startImg(index)">
        </li>
      </template>

    </ul>
  </div>
</div>



<script>
  function imgFunc() {
    return {
      currentImage: 'https://images.pexels.com/photos/5549634/pexels-photo-5549634.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=200&w=400',
      images: [
        'https://images.pexels.com/photos/5549634/pexels-photo-5549634.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=200&w=400',
        'https://images.pexels.com/photos/5101387/pexels-photo-5101387.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
        'https://images.pexels.com/photos/2363832/pexels-photo-2363832.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260'
      ],
      startImg(index) {
        this.currentImage = this.images[index];

        if (index > 0)
          return;

        let i = 0;
        var myvar = setInterval(() => {
          i = (i >= this.images.length - 1) ? 0 : ++i;
          this.currentImage = this.images[i];
        }, 1000);
      },
    }
  }
</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

What is the best way to retrieve web pages from the cache and automatically fill in form data when navigating to them from different pages on my website?

On my website, I have multiple pages featuring forms along with breadcrumbs navigation and main navigation. Interestingly enough, the main navigation and breadcrumbs share some similarities. However, my desire is that when users click on breadcrumb links, ...

How can a server retrieve a file uploaded using FormData and Ajax on a cross-domain upload?

my website is running on localhost:8084 and I need to upload a file to localhost:8086. Below is the JavaScript code: var xhr = new XMLHttpRequest(); xhr.open("post", "http://localshot:8086"+ "?type=ajax",true); xhr.setRequestHeader("X-Reque ...

Which is better to use: sql==true or sql===true?

Hey there, could you please take a look at this and thanks in advance! I'm currently working on developing a system for upgrading buildings in my game. I have set up a universal upgrade div that applies to all buildings. When the player clicks on a bu ...

What steps can be taken to address the issue of the body-parser module being disabled in a node

My API is not functioning properly and I have observed that the body-parser module seems to be disabled in some way. Despite my efforts, I have been unable to find any information on this issue. Please refer to the image attached below for further details. ...

Retrieve JavaScript functions as JSON or text in AngularJS and execute them

Currently, I am working on developing an AngularJS application and have come across a particular challenge that needs to be addressed: After making a web service call, I receive JavaScript code that looks like this: { "script":"function foo(a, b) { c = ...

What is the best way to flip cards with the onClick event in JavaScript?

My cards are currently facing down with the code* provided. What steps should I take to flip them face up using onClick functions? Furthermore, how can I store the IDs in an Array and use them to retrieve images from my image collection? HTML <table s ...

Are there any options for a JavaScript coding platform that can be used on a tablet device?

As someone who frequently travels by train, I recently purchased an Android tablet and have a strong desire to learn JavaScript. While I can read books on my tablet, I am eager to also be able to program on it. Are there any options available for develop ...

Error: The bun.js application encountered a SegmentationFault at line 188

I'm attempting to execute the following command on my current repository, which already has a registry set up in the .npmrc. bun install -y The purpose of the -y flag is to generate the yarn v1 lockfile. However, it's resulting in the followin ...

Tips for displaying two input decorations in Material UI beside one another within a text field

In the Text Field demonstration, I noticed input adornments at the start and end. However, I am looking to have two input adornments at the end specifically. I attempted to add them using endAdornment: {InputAdornment InputAdornment}, but encountered an er ...

The IMDB API is throwing a GraphQL error that says, "ClientError: Unable to retrieve information on the field 'Image' for the type 'MainSearchEntity'."

Seeking suggestions for the top 10 movies related to 'Africa' using the IMDB API demo available here. In my query, I am looking for movie id, title, poster image, and filming location. However, I encounter an error message 'ClientError: Ca ...

Dealing with an unspecified parameter can be tricky - here's how you

Currently, I am in the process of developing an angular application. In this project, there is a specific scenario that needs to be handled where a parameter is undefined. Here's a snippet of my code: myImage() { console.log('test') ...

Passing $index variable from a bootstrap modal window does not work in AngularJS

I'm running into a wall here. My issue involves using ng-repeat to populate a table with two buttons in each row - one for updating the row content and another for uploading files. The upload button triggers a bootstrap modal window where users can se ...

Tips for merging two applications into a single file using Node.js

This code snippet represents the functionality of my chat application. var worker = function(worker) { var http = require('http'); var fs = require('fs'); var app = http.createServer(function(request, response) { f ...

Initiate the process of displaying data on a datetime chart using Highcharts

I am currently developing a yearly chart, but I've encountered a small issue. The chart begins in January, however there is no data available until May. The client specifically wants the chart to only display when there is data available, and unfortu ...

Encountering an issue when deploying a project using node, webpack, express, and mysql to Heroku. The error message states: "Uncaught ReferenceError: regeneratorRuntime is not

I've been going around in circles ever since I started this project, and now the code is all over the place. This is my first time working on a node project without using a framework, and I'm starting to regret not choosing PHP. Anyway, here&apos ...

Unexpected issue on AngularJS application

Encountering issues with incorporating a controller into my page - each time I add it to a DOM element, an error is thrown. Here's the structure of my HTML page: <html data-ng-app="sportsStore"> <head> <title>Sports Sto ...

Is it possible for a jQuery selector to retain its object? What can be done to prevent it

One interesting scenario involves a dropdown element within a container. <div class='container' /> <script> var dropdown = "<select class='multi-dropdown'> ... </select>" </script> Every time the value ...

After extended periods of use, the website experiences frequent crashes

Currently, I am developing a website using a free provider (000webhost) and focusing on integrating a chat feature. To achieve this, I have implemented an interval every 500 milliseconds that reads a file to check for new messages. When a new message is de ...

The resizing of the window does not trigger any changes in the jQuery functions

Here is a snippet of jQuery code that executes one function when the window size is large (>=1024) and another when it is resized to be small. Although the console.logs behave as expected on resize, the functions themselves do not change. This means th ...

Unable to transmit information back to React

Recently stepping into the world of React and Node.js, I have successfully created a function in my Node.js application that executes a Python script using child process. However, I seem to be facing a challenge with my router post method named pythonExecu ...