Can PCFs communicate?

A PCF component is isolated in a sandbox. It gets a piece of the document (a div) where it can play, and it’s allowed to report when the value(s) changed. That’s it. I totally understand that the components has to be in “isolation”, but what if they need to “tell” more?

Platform way: Communication through common attributes

The PCF components are designed to have more than one parameter; a very interesting approach, which I didn’t expect when I’ve started with the pcf development. But I’m really happy for this possibility. That’s a great value for the component itself, and means even more, when different pcf components can have parameters sharing the same attributes. That’s a way to “communicate” with other components: by changing the values of commonly used properties. That will trigger the “updateView” for the other components with the new values.

But that could lead to heavily using “technical” attributes: attributes that are customized only to be able to let the components communicate. And it has also another disadvantage: you must declare the parameters in the manifest, so you must know all of them from the beginning. When you develop generic components, that might not always be the case. Is there another way?

My rescue: 💡window.postMessage()

Since the PCF components are part of a web page, why shouldn’t they use web-communication ( window.postMessage ) to reach the other components? The components don’t know about each other, but they are all “living” in a same window, so they can send messages to everything inside the current window. Every component registered to the “message” event, would get that message.

Of course, when implementing the postMessage, it’s important to follow the rules: define the targetOrigin and filter only the needed messages when receiving them, as stated in the postMessage documentation).

Use case: Stop form saving when a pcf-value is not valid

I came up with this idea, while I was trying to answer a question in the PCF Community: it was about not allowing the form to save, if the pcf value is not valid. Shortly after that I’ve saw that Benedikt Bergmann wrote also a blog about prevent form saving . His approach (based on an idea from Ben Thompson) is a little different: he also uses a boolean technical attribute, but he needs form scripting or business rule to stop the saving. I wanted to try with a pure PCF approach.

There are two parts of the solution:

  1. How to interact with the form?
    • The component can interact with the form only by changing properties values
    • The Form interacts with the data and stops the saving automatically, if the value for a required field is missing.
    • So part one of the solution would be to use a dummy required field, and delete it’s value if the form needs to prevent the saving.
  2. How to make it generic?
    • But what if there are more pcfs on the form that are not valid? Should I make for each pcf another technical attribute “isvalid1”, “isvalid2”, ..?
    • No, I could make only ONE attribute “isValid”, and make a dedicated PCF for it. All other pcfs would register to it, by sending messages.
    • So basically this PCF would only receive messages and change the value of it’s own property to null / true. Since this property is required, the form won’t save the data. As a feedback to the user, it can show the messages received.

So I made the FormGate PCF (I really struggled with the name, but I couldn’t come up with a better one, sorry for that). It’s a technical PCF , that has to be registered on a boolean required field (the blue box in the screenshot below). The other PCFs (in my case the ugly ones in the screenshot) just need to send window.postMessage().

The message sent with postMessage, must contain some properties in the data. This is an example:

{
   messageName: "ORBIS.FormGate",
   fieldName: "field1",
   isValid : false, 
   errorMessage : "Have you checked your field 1"
}

The PCF must know that he is the intended receiver, so it filters on “messageName” (but the default “ORBIS.FormGate” is customizable). The fieldName is a kind of key: each sender must have a unique name (attributeName is a good fieldName). The rest is only the valid state, and the errorMessage that should be shown.

Above the FormGate PCF, with are some pcfs sending messages.

The PCF and the detailed description can be found on my github.

Use case: custom events sent to other pcfs on the form

I think there are some more problems that can be solved with window.postMessage. For instance a dataset pcf component might change some data (create some related records), while the field pcfs on the form are not aware of that. If the dataset pcf sends a message, the fields on the form can attach to this message and refresh the content.

Another example: consider two great PCF components from the pcf.gallery: AttachmentUploader by Rama Rao Koneru and CarouselControl by Ivan Ficko . The first one allows you to upload attachments, and the second one shows them. Nice ones. But the Carousel control cannot know that the AttachmentUploader just created some new attachments, so the user needs to refresh the form in order to see them. If the Uploader would send messages, the Carousel could attach to the messages and automatically refresh. Wouldn’t that be great?

Is it unsupported?

It’s just normal web-communication, so it’s at least not a bad practice. Is not a dirty access to a function inside another frame, no cross-origin problems, is not calling a function that might have been unloaded in the meantime without being noticed ( I remember the old times getting the scary error “cannot execute code from a freed script” 😨).

Since all PCFs are DIVs inside the same window, we don’t have to search for the frame of the others. They are there together: isolated but not alone. I cannot imagine that the PCFs will be in the future rendered in separate IFrames. That wouldn’t make sense. So I think it’s pretty safe too.

The solution checker and appsource checker didn’t report any high issues (except the one web-avoid-eval, that I get as soon as React is included in the project). Actually the PCF sending the message (without react), had only 5 medium issues.

As far as I am aware, it’s supported 😃. In case you know something else, please let me know.

Timing

Since the pcf components are not aware when the others are instantiated, and since the components are created only with the first visit on a tab, the receiver might not be ready in the moment the message is sent .

In the example with form saving, the FormGate PCF should be on the first tab (or the same tab with the “sender”/”validated controls”), otherwise this won’t work.

If it’s important to know if the message was received, you could implement a confirmation message, a handshake. But you cannot be sure that the receiver will be loaded till the end.

In most of the cases is not that important to know that the message is received: if the component is not loaded, it doesn’t show anything, so it doesn’t show old data neather .

What about communicating with the scripts registered on the form?

That’s another story. Of course, it can work the same way. The problem is finding the IFrame where the scripts are loaded. Right now, the pcfs are on the “top” window, and the “Scripts-frame” is an IFrame inside. Sending a message to every frame on the form, we will reach out also the Scripts frame, so the component can at least be notified about the event.

Array.from(window.frames).forEach(frame => frame.postMessage({...}, "*");

But honestly, I wouldn’t do that. The frame nesting might change, and the code will suddenly stop working. And there is still the problem of not knowing, which frame is loaded first, and would need to implement a confirmation, while sending messages in a loop. I think that’s not only unsupported, but also kind of dirty.

I think that right now the only supported way to interact with the form scripting is making use of PCF parameters and changing the data.

Future…

Recently Hemant Gaur, Microsoft Program Manager on Power Apps team, wrote in a PCF Community thread that

Adding 1st class declarative way for controls to communicate events (or behavior) like canvas apps is in our roadmap.

So maybe soon enough, we won’t need the “postMessage” or “technical attributes” anymore. Looking forward to this feature.

___

The featured image is made by combining some images from https://www.pngguru.com/.

2 thoughts on “Can PCFs communicate?

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑