0

My LWC has an LWC:if / else condition in the HTML, but the condition is not determined on the initial load so it loads the default. When the js runs through all the code and the condition result is different to the default, it does not reload the HTML section for the conditional display. I have tried moving the check to various different places (callback/@wire) but nothing seems to work.

The HTML:

<template>
  <lightning-card title="Fee Rules">
    <template lwc:if={canApplyFees}>
      <div slot="actions">
        <lightning-button
          label="Apply Selected"
          onclick={applySelected}
        ></lightning-button>
      </div>
      <div class="slds-card__body_inner slds-var-m-around_medium">
        <lightning-datatable
          key-field="Id"
          data={models}
          columns={columns}
          onrowselection={handleRowSelection}
          onrowaction={handleRowAction}
          column-widths-mode="auto"
        >
        </lightning-datatable>
      </div>
    </template>
    <template lwc:else>
      <div class="slds-var-m-around_medium slds-text-heading_small">
        <div class="slds-var-m-around_medium">
          <p>
            Fees can currently not be applied.
          </p>
        </div>
      </div>
    </template>
    <div slot="footer">
      <lightning-button
        variant="neutral"
        label="Close"
        onclick={closeAction}
        class="slds-m-right_small"
      ></lightning-button>
    </div>
  </lightning-card>
</template>

And the .js is as follows:

import { LightningElement, wire, api } from "lwc";
import { CloseActionScreenEvent } from "lightning/actions";
import canApplyFeeRules from "@salesforce/apex/FeeModelController.canApplyFeeRules"; // Apex method
import { ShowToastEvent } from "lightning/platformShowToastEvent";

//const actions = [{ label: "Show details", name: "show_details" }];
const COLUMNS = [
  {
    label: "View",
    type: "button-icon",
    initialWidth: 75,
    typeAttributes: {
      iconName: "action:preview",
      title: "View",
      variant: "border-filled",
      alternativeText: "View"
    }
  },
    .....
];

//--------------------------------------------------------------------------------
export default class FeeModelSelection extends LightningElement {
  @api recordId;
  models; // Holds the Fee Rule data
  columns = COLUMNS;
  model;
  selectedRows;
  modalPopup = false;

  //canApplyFees;
  get canApplyFees() {
    return this.checkCanApplyFees();
  }

  //----------------------------------------------------------
  connectedCallback() {
    console.log("RecordId in connectedCallback", this.recordId);
    this.checkCanApplyFees();
  }
  //----------------------------------------------------------
  checkCanApplyFees() {
    console.log("RecordId in checkCanApplyFees", this.recordId);
    if (this.recordId !== undefined) {
      canApplyFeeRules({ ipId: this.recordId })
        .then((result) => {
          console.log("canApplyFees", result);
          return result;
        })
        .catch((error) => {
          this.dispatchEvent(
            new ShowToastEvent({
              title: "Error on checking whether Fee Rules can be applied",
              message: error.body.message,
              variant: "error",
              mode: "sticky"
            })
          );
          return false;
        });
    }
    return true;
  }
  //----------------------------------------------------------
  // Fetch the records using Apex
  @wire(getFeeModels)
  wiredModels({ error, data }) {
    console.log("RecordId in @wire", this.recordId);
    //this.checkCanApplyFees();
    if (data) {
      this.models = data;
      this.models = data.map((row) =>
        Object.assign(
          {
            nameUrl: "/" + row.Id,
            Name: row.Name
          },
          row
        )
      );
    } else if (error) {
      console.error("Error fetching Fee Models:", error);
    }
  }
  //----------------------------------------------------------
  closeAction() {
    this.dispatchEvent(new CloseActionScreenEvent());
  }
}

In debugging this is what I get from the console statements. It runs the check too many times due to my trying to get it to work, but the end result of false is the important thing, yet my page displays the default (which I set to true to test). So to me it means it loads the page, using the default setting of true, then the rest of the js runs and returns false, but it doesn't reflect on the page as it never displays the else condition. So it doesn't reload the page. enter image description here

How do I get it to work so the page loads correctly according to the condition?

Update: If I follow @RubenDG's suggestion I get it to work, but only by putting the call into the @wire function. And then it only works the first time I open the LWC.

If I open it again it doesn't work (using the button on the record page) and the recordId is undefined all the way through. Why is this?

enter image description here

The LWC is run from this button (an LWC action) on the record page.

enter image description here

1 Answer 1

0

Calling an Apex method (canApplyFeeRules) from JS results in a Promise, that represent an async operation. What you return from within a then or catch block will be incapsulated in a new Promise, allowing you to chain calls to other promise methods.
Anyway the execution of checkCanApplyFees won't stop waiting that promise, it just run the next line asap, returning always true in your case.

EDITED:
To fix this issue change the getter canApplyFees to an instance variable and set it inside the then/catch block.
Moreover, since it's a quick action and you need to rerun the check every time the user clicks on the button, you need to call checkCanApplyFees in the renderedCallback, instead of the connectedCallback, so to avoid calling it multiple times you also need a flag:

canApplyFees = false;
renderedOnce = false;

//----------------------------------------------------------
renderedCallback() {
    if (!this.renderedOnce && this.recordId) {
        this.checkCanApplyFees();
    }
}
//----------------------------------------------------------
checkCanApplyFees() {
    console.log("RecordId in checkCanApplyFees", this.recordId);
    if (this.recordId) {
      canApplyFeeRules({ ipId: this.recordId })
        .then((result) => {
          console.log("canApplyFees", result);
          this.canApplyFees = result;
        })
        .catch((error) => {
          this.dispatchEvent(
            new ShowToastEvent({
              title: "Error on checking whether Fee Rules can be applied",
              message: error.body.message,
              variant: "error",
              mode: "sticky"
            })
          );
          this.canApplyFees = false;
        });
    }
}

This way as soon as the promise returned by canApplyFeeRules is fulfilled (or rejected) the value of canApplyFees will be set accordingly triggering the rerender of the template.

2
  • that was how I had it first but it didn't work. Or rather, it works if I put the this.checkCanApplyFees(); in the @ wire function (not in the connectedCallBack), but the first time only. If I then close the LWC and open it again (in the same session), it doesn't work anymore. The LWC is called from a button (an action) on a page. I click it to open the LWC window and do the selection (if possible), then close it. If I click the button again it doesn't run the checkCanApplyFees again (whether it's in connectedCallBack or @ wire). Commented Feb 13 at 0:24
  • @Irene I edited the answer. You just have to use renderedCallback instead of connectedCallback Commented Feb 13 at 8:49

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.