1

I am trying to get the records of some object X using wire service by passing a param to wire service. Below is the code,

searchResults.js

isLoading = false;
boatTypeId = '';
@api
searchBoats(typeId) {
    this.notifyLoading(true);
    this.boatTypeId = typeId;
}

@wire(getBoats, {boatTypeId: '$boatTypeId'})
wiredBoats(result) {
    console.log('wired')
    this.boats = result;
    if (result.error) {
        this.boats = undefined;
        this.error = 'Unknown error';
        if (Array.isArray(error.body)) {
            this.error = error.body.map(e => e.message).join(', ');
        } else if (typeof error.body.message === 'string') {
            this.error = error.body.message;
        }
    }
    this.notifyLoading(false);
}

notifyLoading(isLoading) {
    // dispatch doneLoading or loading events based on the status of isLoading
    this.isLoading = isLoading;
    if (isLoading) {
        const loading = new CustomEvent("loading");
        this.dispatchEvent(loading);
    } else {
        const doneLoading = new CustomEvent("doneloading");
        this.dispatchEvent(doneLoading);
    }
}

search.js

// Handles loading event
handleLoading() { 
    this.isLoading = true;
}

// Handles done loading event
handleDoneLoading() { 
    this.isLoading = false;
}

// Handles search boat event
// This custom event comes from the form
searchBoats(event) { 
    const searchBoatTypeId = event.detail.boatTypeId;
    this.template.querySelector("c-boat-search-results").searchBoats(searchBoatTypeId);
}

search.html

 <lightning-layout-item size="12" class="slds-p-top_small slds-is-relative">
    <template if:true={isLoading}>
        <lightning-spinner alternative-text="Loading"></lightning-spinner>
    </template>
    <template if:false={isLoading}>
      <c-boat-search-results onloading={handleLoading} ondoneloading={handleDoneLoading}>
      </c-boat-search-results>
    </template>
  </lightning-layout-item>

Expectation is when searchBoats is called from search.js it will display the loading animation by calling this.notifyLoading(true); (which dispatched loading event handled by search component). And then searchBoats updates the this.boatTypeId which in turn should trigger the wire service to get the this.boats results from getBoats.

What is happening actually is searchBoats successfully gets called and displays the loading spinner. After that wire service never gets invoked and I get infinite loading spinner (because wire service is never invoked code flow never reaches this.notifyLoading(false) in the wire call)

If I remove this.notifyLoading(true); call completely from searchBoats then everything just works fine, which is why it looks like dispatchEvent for loading spinner is blocking the execution of wire service even when the $boatTypeId value is updated.

Need help understand this behaviour and what is actually causing this to happen. Pretty sure I am doing something wrong here.

1

There appear to be several issues with this code:

  1. For the searchResults, you should not assign empty string to the boatTypeId initially - a wire is invoked only once all its dynamic parameters have non-undefined values and because of this you are likely causing an unhelpful initial invocation of the wire, during component initialization, before the searchBoats API property is set.
  2. For the searchResults, the searchBoats API is not defined as a property directly or as a property with getter and setter methods.
  3. For the search, this should interact with the searchResults using API property setting through the template instead of directly invoking functions on the child component.
  4. The loading handling presentation of the spinner should be handled by the child component. The problem you have is that the child component gets destroyed in the search template when template if:true={isLoading}.

Try the following changes:

searchResults

isLoading = true;
boatTypeId;

@api get searchBoats() {
    return this.boatTypeId;
}

set searchBoats(typeId) {
    this.boatTypeId = typeId;
    this.isLoading = true;
}

@wire(getBoats, {boatTypeId: '$boatTypeId'})
wiredBoats(result) {
    this.isLoading = false;
    ...
}

The searchResults HTML should be updated to show the spinner when isLoading is true, or the actual results otherwise.

search HTML should just do something like:

<lightning-layout-item size="12" class="slds-p-top_small slds-is-relative">
    <c-boat-search-results ondoneloading={handleDoneLoading} searchBoats={id}>
    </c-boat-search-results>
</lightning-layout-item>

And have an "id" tracked property in the search component that is set to the value to be searched against by the search results.

| improve this answer | |
  • thanks @Phil. The loading handling presentation of the spinner should be handled by the child component. The problem you have is that the child component gets destroyed in the search template when template if:true={isLoading} even I thought this might be the reason but then isn't this the result of flow already reaching searchResult component and executing searchBoats. I also tried changing the order of execution in searchBoats, where first it changes the value of boatTypeId and then calls notifyLoading routine – Yogesh D Aug 12 at 11:15
  • Not sure why it was down voted. I definitely did look into it and tried to debug it myself before posting this question here. I don't agree that I haven't done any research into it. Either ways I will keep looking into it and see if I find the problem. – Yogesh D Aug 12 at 11:19
  • 1
    I didn't down vote. That said, I believe you should do the refactoring I have suggested in this answer and that it would resolve your problems. – Phil W Aug 12 at 11:20
  • BTW, I believe that the child component actually gets destroyed, because the parent's re-rendering no longer includes it, so even if the wire was initiated before the parent re-renders, by the time a response is available there's no component to receive it. – Phil W Aug 12 at 11:30
  • 1
    Take a look at developer.salesforce.com/blogs/2019/02/… – Phil W Aug 12 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.