Parent-to-Child communication
To enable Parent-to-Child communication, the child component must have a public property or function declared using the @api decorator.
child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
@api childVar;
}
child.html
<template>
</template>
parent.html
<template>
<c-child child-var={parentVar}></c-child>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentVar = 'Hello!';
}
Call a Child function
To call a child function, it is necessary to take into account that this can only be done after the child's component has entered the DOM. So in this example I am using the renderedCallback method.
child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
@api
childFunction() {
return 'Hello!';
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
renderedCallback() {
let childCmp = this.template.querySelector('c-child');
let result = childCmp.childFunction();
}
}
parent.html
<template>
<c-child></c-child>
</template>
2. Child-to-Parent communication
The Child component cannot directly pass data to the Parent component using property, so this can be done by dispatching a custom event from the Child component, and the Parent component must listen for this event.
Child-to-Parent
child.js
import { LightningElement } from 'lwc';
export default class Child extends LightningElement {
renderedCallback() {
this.childFunction();
}
childFunction() {
this.dispatchEvent(new CustomEvent('childevent', {
detail: {
childVar: 'Hello!',
}
}));
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentFunction(event) {
let result = event.detail.childVar;
}
}
parent.html
<template>
<c-child onchildevent={parentFunction}></c-child>
</template>
Child-to-Grandparent
When we have a chain of nested components, we often need to pass data from a child component to the grandparent component. So we need to configure Event Propagation using the bubbles property set to true in dispatchEvent on the intermediate components (in our case, it is the Parent component).
child.js
import { LightningElement } from 'lwc';
export default class Child extends LightningElement {
renderedCallback() {
this.childFunction();
}
childFunction() {
this.dispatchEvent(new CustomEvent('childevent', {
detail: {
childVar: 'Hello!',
}
}));
}
}
child.html
<template>
</template>
parent.js
import { LightningElement } from 'lwc';
export default class Parent extends LightningElement {
parentFunction(event) {
this.dispatchEvent(new CustomEvent('parentevent', {
bubbles: true,
detail: event.detail
}));
}
}
parent.html
<template>
<c-child onchildevent={parentFunction}></c-child>
</template>
grandparent.js
import { LightningElement } from 'lwc';
export default class Grandparent extends LightningElement {
grandparentFunction(event) {
let result = event.detail.childVar;
}
}
grandparent.html
<template>
<c-parent onparentevent={grandparentFunction}></c-parent>
</template>
3. Communication between unrelated components
MyMessageChannel.messageChannel-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>MyMessageChannel</masterLabel>
<isExposed>true</isExposed>
<description>Sends messages to unrelated components</description>
<lightningMessageFields>
<fieldName>value</fieldName>
<description>The value to send to a component</description>
</lightningMessageFields>
</LightningMessageChannel>
Then create 2 unrelated components. The first has an input field and publishes value from the field via the Message Channel. The second subscribes to this Message Channel and displays the value.
component1.html
<template>
<lightning-input onchange={sendMessage}></lightning-input>
</template>
component1.js
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';
export default class Component1 extends LightningElement {
@wire(MessageContext)
messageContext;
sendMessage(event) {
const payload = {
value: event.target.value,
};
publish(this.messageContext, MY_MESSAGE_CHANNEL, payload);
}
}
component2.html
<template>
<p>{value}</p>
</template>
component2.js
import { LightningElement, wire } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import MY_MESSAGE_CHANNEL from '@salesforce/messageChannel/MyMessageChannel__c';
export default class Component1 extends LightningElement {
value;
subscription;
@wire(MessageContext)
messageContext;
connectedCallback() {
this.subscribeToMessageChannel();
}
subscribeToMessageChannel() {
this.subscription = subscribe(
this.messageContext,
MY_MESSAGE_CHANNEL,
(message) => this.handleMessage(message)
);
}
handleMessage(message) {
this.value = message.value;
}
}