pubsub.html은 필요 없습니다.
※ pubsub.js
const events = {};
/**
* Confirm that two page references have the same attributes
* @param {object} pageRef1 - The first page reference
* @param {object} pageRef2 - The second page reference
*/
const samePageRef = (pageRef1, pageRef2) => {
const obj1 = pageRef1.attributes;
const obj2 = pageRef2.attributes;
return Object.keys(obj1)
.concat(Object.keys(obj2))
.every(key => {
return obj1[key] === obj2[key];
});
};
/**
* Registers a callback for an event
* @param {string} eventName - Name of the event to listen for.
* @param {function} callback - Function to invoke when said event is fired.
* @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
*/
const registerListener = (eventName, callback, thisArg) => {
// Checking that the listener has a pageRef property. We rely on that property for filtering purpose in fireEvent()
if (!thisArg.pageRef) {
throw new Error(
'pubsub listeners need a "@wire(CurrentPageReference) pageRef" property'
);
}
if (!events[eventName]) {
events[eventName] = [];
}
const duplicate = events[eventName].find(listener => {
return listener.callback === callback && listener.thisArg === thisArg;
});
if (!duplicate) {
events[eventName].push({ callback, thisArg });
}
};
/**
* Unregisters a callback for an event
* @param {string} eventName - Name of the event to unregister from.
* @param {function} callback - Function to unregister.
* @param {object} thisArg - The value to be passed as the this parameter to the callback function is bound.
*/
const unregisterListener = (eventName, callback, thisArg) => {
if (events[eventName]) {
events[eventName] = events[eventName].filter(
listener =>
listener.callback !== callback || listener.thisArg !== thisArg
);
}
};
/**
* Unregisters all event listeners bound to an object.
* @param {object} thisArg - All the callbacks bound to this object will be removed.
*/
const unregisterAllListeners = thisArg => {
Object.keys(events).forEach(eventName => {
events[eventName] = events[eventName].filter(
listener => listener.thisArg !== thisArg
);
});
};
/**
* Fires an event to listeners.
* @param {object} pageRef - Reference of the page that represents the event scope.
* @param {string} eventName - Name of the event to fire.
* @param {*} payload - Payload of the event to fire.
*/
const fireEvent = (pageRef, eventName, payload) => {
if (events[eventName]) {
const listeners = events[eventName];
listeners.forEach(listener => {
if (samePageRef(pageRef, listener.thisArg.pageRef)) {
try {
listener.callback.call(listener.thisArg, payload);
} catch (error) {
// fail silently
}
}
});
}
};
export {
registerListener,
unregisterListener,
unregisterAllListeners,
fireEvent
};
※ lwc018PubSubSendData.html
<template>
<div class="wrapper">
<lightning-button variant="brand" label="Send Data" title="Primary action"
onclick={sendData} class="slds-m-left_x-small"></lightning-button>
</div>
</template>
※ lwc018PubSubSendData.js
import { LightningElement,wire,track,api } from 'lwc';
import {CurrentPageReference} from 'lightning/navigation';
import {fireEvent} from 'c/pubsub';
export default class Lwc018PubSubSendData extends LightningElement {
@wire (CurrentPageReference) pageRef;
sendData(event){
var eventParam = {name : 'tester01'};
fireEvent(this.pageRef,'pubsubevent',eventParam);
}
}
※ lwc019PubSubGetData.html
<template>
<div class="wrapper">
<p class="sub-t"> 받아온 데이터 : {testMsg}</p>
</div>
</template>
※ lwc019PubSubGetData.js
import { LightningElement,wire,track } from 'lwc';
import {registerListener,unregisterAllListeners} from 'c/pubsub';
import {CurrentPageReference} from 'lightning/navigation';
export default class Lwc019PubSubGetData extends LightningElement {
@wire (CurrentPageReference) pageRef;
@track testMsg;
handleCallback(detail){
this.testMsg = detail.name;
}
connectedCallback(){
/* event 등록 */
registerListener('pubsubevent',this.handleCallback,this);
}
/* event 삭제 */
disconnectedCallback(){
unregisterAllListeners(this);
}
}
'c/pubsub'처럼 파일을 제대로 불러온다면 pubsub 파일 이름은 달라도 괜찮습니다.
출처 : communication-between-unrelated-components-using-publisher-subscriber-pattern-lwc
→ 부모자식 관계가 아닌 서로 상관없는 LWC 사이의 데이터 교환하기
1. force-app>main>default폴더에 messageChannels폴더 생성
2. 해당 폴더에 Sample_String.messageChannel-meta.xml 파일 생성
3. operator, sampleString, sampleData 필드 생성하는 코드 작성
※ Sample_String.messageChannel-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>CountUpdated</masterLabel>
<isExposed>true</isExposed>
<description>Message Channel to pass Count updates</description>
<lightningMessageFields>
<fieldName>operator</fieldName>
<description>This is the operator type of the manipulation</description>
</lightningMessageFields>
<lightningMessageFields>
<fieldName>sampleString</fieldName>
<description>This is sampleString</description>
</lightningMessageFields>
<lightningMessageFields>
<fieldName>sampleData</fieldName>
<description>This is sampleData</description>
</lightningMessageFields>
</LightningMessageChannel>
※ lwc015RemoteControl.html
<template>
<div class="wrap">
<h2>lwc015RemoteControl</h2>
<input onchange={titleChange} class="custom-input" value="Title" />
</div>
</template>
※ lwc015RemoteControl.js
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import String_UPDATED_CHANNEL from '@salesforce/messageChannel/Sample_String__c';
export default class Lwc015RemoteControl extends LightningElement {
@wire(MessageContext)
messageContext;
titleChange(event){
const newString = event.target.value;
const newObj = ['바나나', '사과', '딸기'];
const sendDataValue = {
operator: 'sampleData',
sampleString: newString,
sampleData : newObj
};
console.log('sendDataValue : ', sendDataValue);
publish(this.messageContext, String_UPDATED_CHANNEL, sendDataValue);
}
}
※ lwc015RemoteControl.css
.wrap{
width: 100%;
max-width: 800px;
margin: 10px auto;
background-color: #FFFFFF;
padding: 20px 10px;
border-radius: 5px;
box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}
.wrap h2{
font-weight: bold;
color: #636363;
font-size: 20px;
}
※ lwc016Count.html
<template>
<div class="wrap">
<h2>lwc016Count</h2>
<p>받아온 String 값 : {receivedString}</p>
<p>받아온 Obj 값 : </p>
<template for:each={receivedObj} for:item="item" for:index="index">
<p key={item}>{index} - {item}</p>
</template>
</div>
</template>
※ lwc016Count.js
import { LightningElement, wire, track } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import String_UPDATED_CHANNEL from '@salesforce/messageChannel/Sample_String__c';
export default class Lwc016Count extends LightningElement {
receivedData = null;
@wire(MessageContext)
messageContext;
@track receivedString;
@track receivedObj;
connectedCallback() {
//첫 로딩시 만들었던 MessageChannel 폴더를 확인하는 class로 실행시키기
this.subscribeToMessageChannel();
}
//첫 로딩시 만들었던 MessageChannel 폴더를 확인하는 class
subscribeToMessageChannel() {
this.receivedData = subscribe(
this.messageContext,
String_UPDATED_CHANNEL,
(message) => this.handleMessage(message)
);
}
handleMessage(message) {
//만들었던 필드 불러오기
console.log('message.operator : ', message.operator);
console.log('message.sampleString : ', message.sampleString);
console.log('message.sampleData : ', message.sampleData);
this.receivedString = message.sampleString;
this.receivedObj = message.sampleData;
}
}
※ lwc016Count.css
.wrap{
width: 100%;
max-width: 800px;
margin: 10px auto;
background-color: #FFFFFF;
padding: 20px 10px;
border-radius: 5px;
box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}
.wrap h2{
font-weight: bold;
color: #636363;
font-size: 20px;
}
220926 1번 pubsub 추가