I have a 4 layers LWC component: great-grandparent > grandparent > parent > child. I want to pass an @api property from great-grandparent to display and modify data in child.
Because the property does not display on the parent component so please excuse me for posting the code of grandparent and parent only.
Great-Grandparent Controller
@AuraEnabled
public static List<Sobject> getDatas(Boolean isRecentlyView,
List<String> fields,
String sobjectType,
String query,
Integer limitNum){
try {
if (limitNum != null) {
if (isRecentlyView) {
query = 'SELECT ' + String.join(fields, ', ') + ' FROM ' + sobjectType + ' WHERE LastViewedDate !=null ORDER BY LastViewedDate DESC ';
query += ' LIMIT :limitNum';
} else {
query = query.split('FROM')[1];
query = 'SELECT ' + String.join(fields, ', ') + ' FROM ' + query;
query += ' LIMIT :limitNum';
}
return Database.query(query);
} else return new List<SObject>();
} catch (Exception e) {
throw e;
}
}
Great-Grandparent HTML
<c-grandparent data={parentdata}></c-grandparent>
Great-Grandparent JS
import { LightningElement, api, track, wire } from 'lwc';
import getDatas from '@salesforce/apex/ListviewController.getDatas';
export default class Great-Grandparent LightningElement {
@api limitNum; // receiving value from config xml
@track isLoading = false;
@track fieldcolumns = [];
parentdata = [];
numberOfRecords = '';
isRecentlyView = false;
handleGetData(){
getDatas({
isRecentlyView: this.isRecentlyView,
fields: fields,
sobjectType: this.sObjectType,
query: query,
limitNum: this.numberOfRecords})
.then(result => {
console.log(result);
this.parentdata = result;})
.catch(e => {
console.error(e);})
}
}
Grandparent HTML
<c-parent records={data}
onlistitemdrag={handleListItemDrag}
onitemdrop={handleItemDrop}>
</c-parent>
Grandparent JS
@api data // I have not performed any logic for it here, so I only post the property
Parent HTML
<template>
<ul ondrop={handleDrop}
ondragover={handleDragOver}
style="height:70vh; overflow-y:auto;">
<template for:each={records} for:item="recordItem">
<c-child record={recordItem}
key={recordItem.Id}
onitemdrag={handleItemDrag}>
</c-child>
</template>
</ul>
</template>
Parent JS
import { LightningElement, api } from 'lwc';
export default class Parent extends LightningElement {
@api records;
renderedCallback() {
console.log("Render call back in parent"); //I log to see how it render
console.log('this.records',this.records);
}
handleDragOver(evt){
evt.preventDefault()
}
handleDrop(){
//some logic here
this.dispatchEvent(event)
}
handleItemDrag(evt){
//some logic here
this.dispatchEvent(event)
}
}
=== I tried another way to approach it by update enforces this read-only behavior ===
- Reference resource:
lwc:if does not work with @api property
lwc:if does not work with @api properties
Parent HTML Modified Code
<template>
<ul ondrop={handleDrop}
ondragover={handleDragOver}
style="height:70vh; overflow-y:auto;">
<template for:each={_records} for:item="recordItem">
<c-child record={recordItem}
key={recordItem.Id}
onitemdrag={handleItemDrag}>
</c-child>
</template>
</ul>
</template>
Parent JS Modified Code
import { LightningElement, api } from 'lwc';
export default class Parent extends LightningElement {
_records = [];
get records() {
return this._records;
}
@api set records(value) {
this._records = value;
}
renderedCallback() {
console.log("Render call back in parent"); //I log to see how it render
console.log('this._records',this._records);
}
handleDragOver(evt){
evt.preventDefault()
}
handleDrop(){
//some logic here
this.dispatchEvent(event)
}
handleItemDrag(evt){
//some logic here
this.dispatchEvent(event)
}
}
Result from debug console
this.records
Proxy(Array)
[[Handler]]: ReadOnlyHandler
[[Target]]: Array(5)
length: 5
[[Prototype]]: Array(0)
[[IsRevoked]]: false
Thank you so much for taking a look at my code