11

I have a set of Lightning Components that I want to allow customers to assemble in different layouts and combinations inside the Lightning App Builder. These components interact: when a user clicks on a button in one component I need another component to react. But they do not contain each other.

This question has already been asked in Lightning Events in Lightning Page Context, but the suggested use of application events isn't working for me. Yes, firing and handling application events works fine when there is a single instance on the screen, but when there is more than one instance (e.g. console navigation is used), all instances respond to an event from any instance.

This screen shot illustrates the situation: there are multiple instances of the same Lightning App Builder page (IN-17-000299, IN-17-000298, IN-17-000297) on the screen at once and they each respond to each others events which is not what I want:

Console example

Is there a way to limit the scope of an application event in this Lightning App Builder context? Is there a pattern I can implement to separate out the events? Is there a better way to get the components to interact?

(This answer suggests an approach where the application event propagation is stopped at the container, but in this case I don't have control over the container.)

10
+100

Application-level events certainly are what Salesforce recommends for the use case of components that will be "App Builder siblings" and need to talk to one another.

I think you won't be able to limit which components see the event, but you can limit which ones respond to it. If I understand correctly your "pitcher" and "receiver" are independent components you expect an end-user to be able to put on a page together and talk to one another.

For the use case where the admin has put multiple groups on the same page, maybe you could put a string identifier field on the component (call it a name, channel, key, what have you) and expose it to App Builder via Design. Then you would instruct admins, if there will be more than one interacting pair, please fill in the identifiers in matching pairs/groups so it knows who's who. In terms of implementation, every event you fire could include the identifier as an attribute so you can check for it.

For the console use case, you could include lightning:workspaceAPI in the components. On init, use getEnclosingTabId() and hold onto that (returns false if not in console tab). When firing an event, pass a "tab ID" attribute. When catching it, verify both the tab ID and the other identifier match.

Reference: https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_lightning_getEnclosingTabId.htm

If you find any other use cases not covered by these, then just consider, is there something unique that you can use (or provide) to determine whether an instance is the wrong recipient?

  • Thanks Charles what you suggest makes sense. Its a pity if there isn't a platform mechanism for this though as it means adding the identifier to the components (using different logic for the console and non-console case), and to the events and filtering on it in every event handler. – Keith C Dec 17 '17 at 11:21
  • True it's a bit of a hassle filtering application level events. For lack of being able to get a parent reference though, I can't think of a better way. If you want to avoid the wasted cycles of every instance catching the event to filter it, maybe there's a useful pattern involving a service component that you embed in every custom component that needs to message. Each component, on init, would register itself with the service component; the service component would index those registrations and be able to deliver messages selectively. – Charles T Dec 17 '17 at 15:00
1

I'm successfully using a combination of previous answers (workspaceAPI and unique names for components to limit publishers & subscribers).

In addition a simple pattern that works fine for some uses, especially for components on record pages is to have the component implement

force:hasRecordId

SFDC docs for the lightning interface

If the components should only listen to events related to a specific record, make that part of the event payload and let subscribers react accordingly. In the console, an alternative but similar approach when you want all your subtabs to listen to events to a primary tabs events, let the primary tab publish the records id in the event and have the subtabs simply check window.location if it contains the id-String. This has the advantage of working in lightning app pages which aren't record pages where the workspaceAPI for some reason currently does not work.

  • Thanks Martin. I've started the changes to use the getEnclosingTabId as the filtering factor. Good to know that others have used this sort of approach. – Keith C Dec 22 '17 at 15:41
  • "lightning app pages which aren't record pages where the workspaceAPI for some reason currently does not work" - oof that's good to know. If your instances of Lightning app pages in console need their children to know of unique containers, maybe you can use a custom template component for the app page. That way the template can generate a unique random identifier on init, and handle a component-level event from its children requesting that identifier. (Not sure which pattern to use to pass a value back down but I'm sure there's something.) – Charles T Dec 23 '17 at 16:06
0

Have you tried stopPropagation()? Take a look at the following resource Application Event handling and limiting

  • Thanks for answering - its a good idea. But there is a section at the end of the question that flags my problem with that approach: I would need (I think) the container supplied by the App Builder to make the stopPropagation call but there is no way to modify that (AFAIK), – Keith C Dec 22 '17 at 10:01
  • Oh.Fine In such case you may send any identifier as a parameter from the component which fires the event. And the handler which matches the identifier should only handle the event. – A.Bretto Dec 22 '17 at 10:10
  • Yeah that's looking like what is needed. Adds quite a bit of ugliness to the code though... – Keith C Dec 22 '17 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.