2

brief app structure(see image): "Line item" child components list on the right (just one 1601xCC5Bulk on this pic), container with pallets on the left. <<Allocate btn opens another child modal with a form (if:true..) this form's picklist uses @wire apex to show only empty pallets, so it's refreshed by form's controller itself after DML. enter image description here

problem arises when changing amount of pallets by a parent for example, using red button on the right. this DML deletes the container along with pallets.

But if the hidden form gets opened again, old pallet values are still present as picklist values, i need to refresh that data. but this child is hidden, so unreachable by standard: parent -> querySelector(child2).method()

  • Sorry for newb question: Is there a way to access hidden component's methods?
  • I was also thinking of moving the call to Apex query up to the parent component (easy to trigger), then passing it down to child modal as an api argument, so when modal appears it'll get updated data. this feels a bit wrong to do, as parent lifts child's burden.(maybe i'm wrong)
  • I was also thinking of using child's renderedCallback for that apex query, but afraid of infinite render loops?
  • Disabling caching of auraEnabled apex would be a nice thing, but seems impossible.

Here is the bare bones markup, showing only all involved parts

===PARENT (with 2 children)===

HTML

<template for:each={lineItems.data} for:item="lineItem">
   <lightning-layout-item key={lineItem.Id} size="12">
     <c-packing-list-line-item-card lineitem={lineItem} onallocatebuttonpress={openAllocationModal}></c-packing-list-line-item-card>
   </lightning-layout-item>
</template>

<template if:true={isLineItemModalOpen}>
     <c-packing-list-allocation-modal recordid={recordId} oncloseallocationmodal={closeAllocModal} onproductallocated={refreshData}></c-packing-list-allocation-modal>    
</template>

JS

openAllocationModal(e) {
        this.editItemId = e.detail;
        this.isLineItemModalOpen = true;
    }
closeAllocModal() {
        this.isLineItemModalOpen = false;
    }

===CHILD 1: packing-list-line-item-card=== (the one on the right, showing product details, passes id to modal)

HTML

<lightning-button variant="brand" label="<< Allocate" data-itemid={lineitem.Id} onclick={openAllocationModal}></lightning-button>

JS

openAllocationModal(e) {
        const selectEvent = new CustomEvent('allocatebuttonpress', { detail: e.target.dataset.itemid });
        this.dispatchEvent(selectEvent);
    }

===CHILD 2: Allocation Modal (conditional display)===

HTML

<template if:true={showInsertButton}>
                <button class="slds-button slds-button_brand" onclick={handleAllocationInsert}>Insert</button>
            </template>

JS (you are probably only interested in closeModal(){}, other stuff is for completeness)

handleAllocationInsert() {
[...]
createRecord(recordInput)
.then((allocId) => {
  this.showToast('success', 'Success', 'Product Allocated');
  this.handleInsert(this.palletValue);
  this.refreshPallets();
})
.catch((error) => {
  this.showToast('error', 'Error creating record', error.body.message);
  this.closeModal();
});

}

closeModal() {
        // On save parent closes modal
        console.log('closing 1');
        const selectEvent = new CustomEvent('closeallocationmodal');
        this.dispatchEvent(selectEvent);
        this.spinner = false;
    }

    handleInsert(palletValue) {
        // On save parent refreshes container view
        const selectEvent = new CustomEvent('productallocated', {
            detail: this.palletcontainers[palletValue].containerId
        });
        this.dispatchEvent(selectEvent);
        this.closeModal();
    }

5
  • Thanks. just added a paragraph in the beginning Aug 17, 2020 at 18:44
  • hmm now I got your problem, so how are you hiding the palette container? and how are you deleting them? can you please add those code snippets? Aug 17, 2020 at 19:00
  • i was trying to be concise. feel free to comment on poor architecture. this is how i understood LWC dev guide Aug 17, 2020 at 19:48
  • @Dextersecret So, all the code you have given is related to the right side section of screenshot. The parent component contains the line item (with <<Allocate button), Delete Container button, Auto-Assign button, Refresh button etc, along with the hidden modal component (i.e., CHILD 2: Allocation Modal or c-packing-list-allocation-modal). Is my understanding correct?
    – arut
    Aug 17, 2020 at 20:07
  • @arut yes, correct. for the sake of simplicity, the stuff on the left is not covered. (Container=child,Pallets=grandchild). If there is any better best practice of working with a modal, let me know. Aug 17, 2020 at 20:34

1 Answer 1

5

Sorry for newb question: Is there a way to access hidden component's methods?

No. The child is physically removed from the DOM and no longer exists at all (except possibly in a component cache).

I was also thinking of moving the call to Apex query up to the parent component (easy to trigger), then passing it down to child modal as an api argument, so when modal appears it'll get updated data. this feels a bit wrong to do, as parent lifts child's burden.(maybe i'm wrong)

This is actually a very standard way of doing this. The child only needs to worry about showing data, which is what it's designed to do. It's generally a good idea to get/set data as high in the component hierarchy as possible (but no higher than necessary).

I was also thinking of using child's renderedCallback for that apex query, but afraid of infinite render loops?

Bad idea, you'll get infinite loops, as you expect. However, using the component's connectedCallback could make sense here. This event is only called when a component is added ore moved in the DOM, so it wouldn't have infinite loop problems.

Disabling caching of auraEnabled apex would be a nice thing, but seems impossible.

It's perfectly possible, but I would consider this a last resort. Most of the time, the data isn't changing until the user does something, so caching can improve performance. That said, your design also appears to not need frequent calls, so disabling caching is probably acceptable as well.


In conclusion, I'd say controlling the data from the parent would be the easiest solution. This is also the generally acceptable solution in most cases, as child components typically only work with the data they're given from the parent. For example, lightning-input doesn't do anything with the server directly, but communicates changes to the parent via events. It's a perfectly natural design to use.

If you want the children to continue doing the work, that's fine, too, just have a refreshApex call in your connectedCallback, or disable caching. Either should resolve your problem, although you may want to test on a large data set to see which of the options available to you offer the best performance.

2
  • 1
    Thank you, fantastic mr Fox! This advice (passing data to children) unties my hands *sigh of relief I have not seen much professional code yet, being a solo self taught admin->dev, so still grasping architectural principles. Aug 17, 2020 at 20:43
  • @Dextersecret Glad to help! Good luck on your adventures in programming. I've been doing this ever since elementary school in some form, and I just love programming. The more you experiment and research, the better your code will get with time, just give it a bit. Your question shows that you definitely have the potential to be a great programmer, so don't get discouraged.
    – sfdcfox
    Aug 17, 2020 at 21:12

You must log in to answer this question.

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