1

My VF page is directly embedded into the utility bar. As I have a WebSocket used to stream some events, I would like to find a way to use LMS to stream those events to LWC and Aura components. On my LWC component side I'm using the application scope right now.

I found that LMS works in both directions when handling click events.

I can't figure out the approach to stream LMS messages, mainly from VF to LWC. As far as I understand it needs some user interaction. Is that a restriction? Is there a way to skip user interaction when we need to stream in different LMS message channels. I have done a simple hacky solution, but the approach is just terrible, IMO.

Is there any better approach that is part of the best practices? Or at least how could I turn it into a mixin or is it possible to be converted to pubsub?

Are the any events that could be triggered and listened to so that sending the LMS message could work?

Hacks that I've tried so far include:

var event = new Event('click',{bubbles:true,composed:true});
element.dispatchEvent(event);
var event = new PointerEvent('click',{bubbles:true,composed:true});
element.dispatchEvent(event);

But the problem with both them that only the onClick function is executed. When it tries to send the LMS message it is not received on the subscriber function.


Terrible Hacky Solution:

This solution transfers counter from VF page to LWC component (WIP).

Test.messageChannel-meta.xml:

    <?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
    <description>Message Channel to update connectivity state</description>
    <isExposed>true</isExposed>
    <lightningMessageFields>
        <fieldName>test</fieldName>
    </lightningMessageFields>
    <masterLabel>Test</masterLabel>
</LightningMessageChannel>

Test.page:

<apex:page controller="TestController">
    <apex:form>
        <apex:outputPanel id="counter">
            <!-- <apex:outputText value="Watch this counter: {!count}"/> -->
            <input type="hidden" value="{!count}" placeholder="hidden" name="hidden" class="test"/>
            <script>
                var testE = document.querySelector('input.test');
                var c = {
                    call: sforce.one.publish,
                    test:'{!$MessageChannel.Test__c}'
                };
                function lms(newValue, oldValue) {
                    c.call(c.test, {test: 'changed from ' + oldValue + ' to ' + newValue + '!'});
                }
                if (document.readyState === 'complete') {
                    lms(testE.value,'');
                }
        
            </script>
        
        </apex:outputPanel>

        <apex:actionPoller action="{!incrementCounter}" reRender="counter" interval="5"/>
    </apex:form>

</apex:page>

Test.page-meta.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ApexPage xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <availableInTouch>true</availableInTouch>
    <confirmationTokenRequired>false</confirmationTokenRequired>
    <label>Test</label>
</ApexPage>

lwcTest.html:

<template>
    <lightning-card title={title} icon-name="custom:custom19">
        <div slot="actions">
            <span class="lightning">LWC</span>
        </div>
        <p>Message from VF: {test}</p>
    </lightning-card>
</template>

lwcTest.js:

import { LightningElement, track,wire } from 'lwc';
import Test from "@salesforce/messageChannel/Test__c";
import {
    subscribe,
    // unsubscribe,
    APPLICATION_SCOPE,
    MessageContext
} from 'lightning/messageService';
export default class LwcTest extends LightningElement {
    @wire(MessageContext)
    subscribeContext;
    subscription = null;
    @track
    test='';
    connectedCallback() {
        this.subscribeToChannel();
    }
    subscribeToChannel() {
        if (!this.subscription) {
            this.subscription = subscribe(this.subscribeContext,
                Test, (message) => {
                    this.handleTest(message);
                }, { scope: APPLICATION_SCOPE }
            );
        }
    }

    handleTest(message) {
        const {
            test: t,
        } = message;
        this.test = t;
    }

}

lwcTest.js-meta.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__UtilityBar</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__UtilityBar">
          <property name="title" type="String"/>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>
4
  • Haven't tried your specific scenario, but sometimes you can execute the click function (developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click) on some HTMLElement instance in JavaScript in lieu of an actual user interaction. Have you tried that yet? Commented Jan 30 at 14:10
  • well, I have tried: var event = new Event('click',{bubbles:true,composed:true}); element.dispatchEvent(event); and replacing it with PointerEvent as well. The clicks work on themself, but the LMS message is not transmitted Commented Jan 30 at 14:26
  • What about simply element.click()? Commented Jan 30 at 18:04
  • I will check that tomorrow, but I guess it is more complicated. I've updated my question so that includes one simple approach using some DOM magic. Commented Jan 30 at 20:35

0

You must log in to answer this question.