Receiving Server-Side Messages in Client-Side Code on a Creatio Freedom UI Page

In a previous article I outlined how to send a message from server-side code, such as from a process script task, an entity subprocess, or a configuration service, and receive this message in client-side code. This article will show how to receive server messages in a Freedom UI. Refer to the previous article to see how to send the message in server-side code (this article will only focus on receiving the message in the Freedom UI page)

Sending a Message from Server-Side C# to Client-Side Javascript in Creatio

First of all, there might be different ways to do this in a Freedom UI page. Since Freedom UI pages are relatively new, I’m still discovering things about different ways to do things using a newer method specifically for Freedom UI. However, this equivalent of the previous method does work as expected.

To receive a server message in client-side code, you need to register a function to receive the message, but you also need to unregister it when the page gets destroyed as well. In a Freedom UI page, you’re working with “handlers”, not functions. So, in order to keep a reference to the function registered, so we can later unregister it, we’ll use an attribute to save the function in. In the page code, locate the viewModelConfig. If there’s already an “attributes” node, we’ll add our attribute under that. If there isn’t an “attributes” node, we’ll add that first. We’ll be calling our attribute “ServerMessageReceivedFunc”. The attribute will look like the following:

viewModelConfig: /**SCHEMA_VIEW_MODEL_CONFIG*/{
	"attributes": {
		"ServerMessageReceivedFunc": {}
	}
}/**SCHEMA_VIEW_MODEL_CONFIG*/,

Now add a handler for the “crt.HandleViewModelInitRequest” request, which is similar to the onEntityInitialized. In it, you’ll create a function and place in that attribute, then wire it up for receiving server messages:

{
	request: "crt.HandleViewModelInitRequest",
	handler: async (request, next) => {
		request.$context.ServerMessageReceivedFunc = async function(event, message) {
			if (message.Header.Sender === "SomeMessageId") {
				// place code here to respond to the server message
				// note: inside this function, request.$context will be the `this` scope
				// for example, this.someAttributeName = "Something"
			}
		};
		Terrasoft.ServerChannel.on(Terrasoft.EventName.ON_MESSAGE, (await request.$context.ServerMessageReceivedFunc), request.$context);
		return next?.handle(request);
	}
}

Now, we’ll add the code to unregister the function when the page gets destroyed in the “crt.HandleViewModelDestroyRequest” request:

{
	request: "crt.HandleViewModelDestroyRequest",
	handler: async (request, next) => {
		Terrasoft.ServerChannel.un(Terrasoft.EventName.ON_MESSAGE, (await request.$context.ServerMessageReceivedFunc), request.$context);
		return next?.handle(request);
	}
}

As I mentioned earlier, there might be a more “Freedom UI way” to do this that I’ve not yet discovered. However for now, the above gets the job done and works great on Freedom UI pages.

Want content like this delivered to your inbox? Sign up for our newsletter!
ABOUT THE AUTHOR

Ryan Farley

Ryan Farley is the Director of Development for Customer FX and creator of slxdeveloper.com. He's been blogging regularly about SalesLogix, now Infor CRM, since 2001 and believes in sharing with the community. His new passion for CRM is Creatio, formerly bpm'online. He loves C#, Javascript, web development, open source, and Linux. He also loves his hobby as an amateur filmmaker.

11 Comments

  1. Hi Ryan, thanks so much for these articles! Is there any chance you have a moment to outline how to use this in conjunction with the refreshing/reloading of a Freedom UI datasource (https://customerfx.com/article/refreshing-reloading-page-or-list-data-on-a-creatio-freedom-ui-page/)? I’ve tried combining them, but sdk.HandlerChainService.instance inside the HandleViewModelInitRequest handler doesn’t seem to work. How can we trigger the datasource reload upon receipt of a server side message (ie. a script task in a process)? Thanks!

    Reply
    • Hi Luke,

      The reason why the refresh isn’t working is because the context has been lost (so the HandlerChainService has as well). There’s two changes you need to make in order for this to work.

      First of all, the article sets up the function that gets called from the server-side message as an anonymous arrow function. The problem that creates is arrow functions don’t get their own context/scope so this makes it impossible for you to get a reference to the page (since you’ve lost the request.$context by that point). However, if you change that to an actual function the request.$context becomes “this” inside the function because the wiring up of the function using Terrasoft.ServerChannel.on passes request.$context as the “this” scope. It makes sense to use it like that in any case, so I’ve updated the article to use it in this way.

      Second, now that you’ve retained the request.$context (as “this” inside the function), you can pass that along to the HandlerChainService request to refresh. Refer back to that article and you’ll see the context being included in the call (remember, for this scenario of receiving a server message, your context will be “this”).

      Lastly, there’s a new feature coming in 8.0.7 that will make this unnecessary for simply refreshing after an object was updated in a process, etc. There will be a new option in objects that you can set to auto-refresh – by simply setting this option, any server-side change will send the message to the UI and the page bound to that object will refresh automatically.

      Ryan

    • Sensational, that did the job, I much appreciate the both quick and detailed response.

  2. Hello, colleagues.
    I faced a problem with the client JS Freedom UI. I use the code based on this example. It adds websocket listener on the crt.HandleViewModelInitRequest and remove it on the crt.HandleViewModelDestroyRequest. But if I click on another section (not Close button), crt.HandleViewModelDestroyRequest does not happen, and then the page opens next time, listener will be added again.
    Did anybody face the same problem?

    Reply
  3. Hi Ryan, is it possible to call a handler when reciveing a message? Thank you!

    Reply
    • Yes. You would use the HandlerChainService to execute the request when the service message is received. You’ll need to add the DevKit dependency:

      define("UsrMyCustomEntity_FormPage", /**SCHEMA_DEPS*/["@creatio-devkit/common"] /**SCHEMA_DEPS*/, 
      function/**SCHEMA_ARGS*/(sdk)/**SCHEMA_ARGS*/ {
          return {
              // ... the rest of the page here
          };
      });

      Then you can execute the request. Note, if the request requires passing the $context, in this article I am setting the request.$context as the this context, so getting the $context you’d just use this

      const handlerChain = sdk.HandlerChainService.instance;
      await handlerChain.process({
          type: "crt.SomeRequest",
          $context: this,
          // etc
      });

Submit a Comment

Your email address will not be published. Required fields are marked *