1

parentCmp.html

<template>

 
    <c-progress-cmp total-steps={currentStep} current-step={currentStep}></c-progress-cmp>
 

   <template if:true={showFirstComponent}>
    <c-first-component></c-first-component>
   </template>

   <template if:true={showSecondComponent}>
    <c-second-component></c-second-component>
   </template>

</template>

parentCmp.js

@track currentStep;
@track totalSteps;

export default class parentCmp extends LightningElement {

         subscribeToMessageChannel() {
            if (!this.subscription) {
                this.subscription = subscribe(
                    this.messageContext,
                    bondPortalChannel,
                    (message) => this.handleMessage(message), {
                    scope: APPLICATION_SCOPE
                }
                );
            }
        }

        unsubscribeToMessageChannel() {
        unsubscribe(this.subscription);
        this.subscription = null;
        }

        connectedCallback() {
            this.subscribeToMessageChannel();
        }

         disconnectedCallback() {
         this.unsubscribeToMessageChannel();
        }

        handleMessage(message) {
        this.showFirstComponent=false;
        this.showSecondComponent=false;

        switch (message.data) {
            case 1:
                this.showFirstComponent=true;
                this.currentStep = 1;
                this.totalSteps = 10;
                break;
            case 2:
                this.showSecondComponent=true;
                this.currentStep = 2;
                this.totalSteps = 15;
                break;
    }


}

progressCmp.html

HTML

<lightning-progress-indicator current-step={currentStep} type="base" variant="base">
    <template if:true={steps} for:each={steps} for:item="step" for:index="index">
        <lightning-progress-step key={step} value={step}></lightning-progress-step>
    </template>
</lightning-progress-indicator>

progressCmp.js

JS


@api totalSteps;
@api currentStep;

connectedCallback() {
    for (let index = 1; index <= this.totalSteps; index++) {
        this.steps.push(index);
    }
    if (this.steps.length > 0){
        this.currentSteps = Number(this.currentSteps);
    }
}

renderedCallback() {
    let tempTotalStep = this.applicationRecord.SL_Total_Steps__c;
    this.steps=[];
    for (let index = 1; index <= tempTotalStep; index++) {
        this.steps.push(index);
    }
}
1
  • How do you change steps count? Could you please edit the question adding the related code (HTML and JS)? Please note that in the renderedCallback method tempTotalStep is a local variabile and it's never defined, so it's undefined. If you have an instance variable called tempTotalStep, you should change it to this.tempTotalStep.
    – RubenDG
    Aug 31, 2023 at 12:46

1 Answer 1

2

Changing the state of the component in renderedCallback is unsupported. This would cause an infinite loop to occur. Instead, set up the steps as the result of an event handler or asynchronous code.

As noted in a comment, tempTotalStep is never defined, which saved you from the infinite loop scenario.

Here's an example that should work:

 <lightning-progress-indicator
    current-step={StatusBarStep}
    type="base"
    variant="base"
  >
    <template
      if:true={steps}
      for:each={steps}
      for:item="step"
      for:index="index"
    >
      <lightning-progress-step
        key={step}
        value={step}
      ></lightning-progress-step>
    </template>
  </lightning-progress-indicator>
  <lightning-button label="Increase Steps" onclick={incrementStepCount}></lightning-button>
import { LightningElement } from 'lwc';

export default class DemoComponent extends LightningElement {
  StatusBarStep = 1;
  steps;
  totalSteps = 5;
  connectedCallback() {
    this.buildSteps();
  }
  incrementStepCount() {
    this.totalSteps++;
    this.buildSteps();
  }
  buildSteps() {
    this.steps = [];
    for (let i = 1; i <= this.totalSteps; i++) {
      this.steps.push(i);
    }
  }
}

Edit based on comments and updates:

Change the @api totalSteps to:

#totalSteps; 
@api get totalSteps() { 
  return this.#totalSteps; 
} 
set totalSteps(value) { 
  this.#totalSteps = value; 
  this.buildSteps(); 
}

When the property changes, the setter will rebuild the steps, and it should work as you expect.

7
  • sorry I missed the declartion of tempTotalStep in post but in my orginal code declartion is there and code is going infinite loop Aug 31, 2023 at 13:20
  • this code is child component we are calling this child component in parent component. So ConnectedCallback is not calling every time. Aug 31, 2023 at 13:23
  • @saivinaymanapuram this is expected, as I said. The array increases in size, which triggers renderedCallback, which increases the array in size, which triggers renderedCallback, ad infinitum. In my demo, a button click is needed to increase the size. You can use either asynchronous code or in response to an event, but do not use renderedCallback to modify any property of the component that will cause another render cycle.
    – sfdcfox
    Aug 31, 2023 at 13:23
  • @saivinaymanapuram In that case, you'd have a public property or method that you can update to change the size. Can you please edit your question to include all relevant code?
    – sfdcfox
    Aug 31, 2023 at 13:24
  • updated the relavant code. Here total steps will be updated dynamically based on currentStep and we are using LMS for communication between the components and Since progress bar is already in the DOM. If total steps are changed it is not rerendering. Please let me know if you have any possible solution. Aug 31, 2023 at 13:47

You must log in to answer this question.

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