2

I have been getting one weird error. Basically, I am trying to create one Carousel component in LWC. EVerything works well until i call the method which is going to auto-slide it. It starts throwing Getting Uncaught TypeError: this.showSlides is not a function .

Here is my code:

    import {
    LightningElement,
    track,
    api,
    wire
} from 'lwc';
import getBanners from '@salesforce/apex/test.getBanners';
import test from '@salesforce/resourceUrl/test';
export default class test extends LightningElement {
    @track result;
    @track target=[];
    @track slideIndex=0;
  
    @track slides;
    @track dots;
   @track numbers=[];
   @track carousel=1;
   @track hasRendered = false;
   


   @wire(getBanners, {
       
})
wiredResult({
    error,
    data
}) { 
    if(data) {
        this.result=data;
        console.log('RESULT LENGTH'+this.result.length);
        for (var i = 1; i <= this.result.length; i++) {
            this.numbers.push(i);
            
          }
       
          console.log('this.numbers Wired'+this.numbers.length);
       
        this.error = undefined;
       
    }
};
       
       
       
   connectedCallback(){
   
   }

  
    renderedCallback() {
     if(!this.hasRendered){
         console.log('inside first render');
         this.addStyle();
         this.showSlides(this.carousel);
         this.hasRendered=true;
     }
     if(this.hasRendered){
        console.log('inside true render');
        this.addStyle();
        this.showSlides(this.carousel);
       this.startSlideShow(this.carousel);
     }
      //
       // console.log('this.numbers Rendered Call Back'+this.numbers.length);
       // this.showSlides(this.carousel);
       
     
        //this.startSlideShow();   
        
       
       
    }

    
     
   
addStyle() {
    
    const divs = this.template.querySelectorAll('.slds-box');
    console.log('divs length'+divs.length);
    Array.from(divs).forEach(div => {
        const index = Number(div.getAttribute("data-index"));
        
        // Note: change this to whatever property you want
        div.style.backgroundImage = 'url()'
    });
   
    
}

showSlides(carousel) {
    var i;
    //if(this.hasRendered == true){
        this.carousel=carousel;
        var  n=carousel;
        this.slideIndex =carousel;
        this.slides  = this.template.querySelectorAll('.mySlides');
        console.log('slides'+this.slides.length);
        console.log('slides'+JSON.stringify(this.slides));
        this.dots = this.template.querySelectorAll('.dot');
         
         console.log('dots'+ this.dots.length);
         console.log('dots'+ this.dots);
         if (n >  this.slides.length) {this.slideIndex = 1}   
         if (n < 1) {
            this.slideIndex = this.slides.length;
        }
         for (i = 0; i <  this.slides.length; i++) {
            this.slides[i].style.display = "none";  
            //this.template.querySelector(this.slides[i]).classList.add('displayclass'); 
         }
        // this.slideIndex++;
         
        
        for (i = 0; i <this.dots.length; i++) {
            this.dots[i].className = this.dots[i].className.replace(" active", "");
           // this.template.querySelector(this.dots[i]).classList.remove('active'); 
      }
      console.log('this.slideIndex'+this.slideIndex);
      console.log('this.slideIndex'+this.slides);
      if(this.slides[this.slideIndex-1]!=='undefined' && this.slides[this.slideIndex-1]!=null){
          console.log('inside if');
          console.log('inside if'+this.slides[this.slideIndex-1]);
        this.slides[this.slideIndex-1].style.display = "block"; 
      }
      if(this.dots[this.slideIndex-1]!=='undefined' && this.dots[this.slideIndex-1]!=null){
        console.log('inside if 1');
        console.log('inside if'+this.dots[this.slideIndex-1]);
        this.dots[this.slideIndex-1].className += " active";
      }
    
     //this.template.querySelector(this.slides[this.slideIndex-1]).classList.add('displayBlock'); 
     //this.template.querySelector(this.dots[this.slideIndex-1]).classList.add('active'); 

    //}
  
    // // Change image every 2 seconds
    //setTimeout(this.showSlides(), 2000);
  }
  
startSlideShow(carousel1){
    //console.log('this.numbers slide show'+this.numbers.length);
    console.log('carousel slide show'+carousel1);
    if(this.numbers){
        if(this.numbers.length> 1){
            setInterval(function() {
            
              if(carousel1 < this.numbers.length){
                carousel1 = carousel1 + 1;
                
                  this.showSlides(carousel1);
              }else{
                carousel1 = 1;
                 
                  this.showSlides(carousel1);
              }
            }, 5000);
        }
    }
   
}
currentSlide(event){
 
    console.log('this.numbers'+this.numbers);
    var carousel = event.target.dataset.carousel; 
    console.log('carousel'+carousel);
    this.showSlides(carousel);
}


  
}

here is my HTML code:

    <template>
    <div class="slideshow-container" >
        <template for:each={result} for:item="res" for:index="index">
            <div class="mySlides fade" key={res.Id}>
                <div data-index={index} 
                     class="slds-box slds-box_x-small slds-text-align_center slds-m-around_x-small">
                    <div>
                        {res.Id} {res.Comments__c}
                        
                    </div>
                </div>
            </div>
            
        </template>
       
    </div>
    <div style="text-align:center" >
        
    <template for:each={numbers} for:item="num" for:index="index">
       
        <span class="dot" onclick={currentSlide} data-carousel={num} key={num}></span> 
      
    </template>
</div>
  
</template>

before i started getting this, i was getting cannot read length of undefined at line number 147 so i changed it to any random number to see if it goes away. Don't know why i am getting this when i am clearly setting values in Numbers array on load itself. Still, i continued to get that error. When i changed to to a certain random number like 5 or 6 to get past it. Now it throws 'Uncaught TypeError: this.showSlides is not a function in LWC' when this method is clearly defined.

Any help will be much appericiated.

1 Answer 1

1

The problem is caused by Javascript function scope. In the instance you are calling it, this is referring to a different this from the main Class context.

A couple of ways you could fix this - save a reference to the outer this in your startSlidShow method ie:

let self = this;
...
self.showSlides(carousel1);

Or (my preferred technique) use an arrow function. Arrow functions have a special property in that they inherit the enclosing this where they are declared. ie:

//***notice arrow function below***
startSlideShow(carousel1) {
  if (this.numbers && this.numbers.length > 1) {
    setInterval(()=>{
      this.showSlides(carousel1 < this.numbers.length ? carousel++ : 1);
    }, 5000);
  }
}
2
  • Thank you So much Caspar... You saved my day. Commented Jun 28, 2020 at 17:07
  • One more thing i wanted to ask is when i simply call this.startSlideShow after i uodated this function with arrow function that wrote it is working fine. But i wanted to call it inside setTimeOut so that i keeps on sliding like this setTimeout(this.startSlideShow(this.carousel).bind(this), 3000);but when i call it like this it again starts giving bind error. How do i fix this? Commented Jun 28, 2020 at 17:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .