Is there a handler used when loading a List element for the first time or when reloading the list, including after changing quick filters? The crt.LoadDataRequest handler appears to only be called when reloading the list or loading in additional records via the infinite scroll mechanic, but not on the first load of the data or when reloading the data after quick filters are changed, so it does not fit the need.

 

What I'm looking to do is to intercept the initial loading of the data for the list to perform some async task, and once that async task has been completed allow the load to resume as usual. This should be triggered when the page first loads the list in, and whenever the user clicks to reload the list manually or changes quick filters that change the list data, but shouldn't be triggered on the infinite scroll.

Like 1

Like

4 comments

Hello,
 

The initial data loading request 'crt.LoadDataRequest' was not included in this step because it’s part of the system's core loading process, ensuring that essential page elements are set up first.

 On subsequent loads, the system publishes 'crt.LoadDataRequest' where users can apply their customizations.
 

Currently, there’s no default handler to directly intercept the system’s initial load, but there are other options for customization depending on the user’s needs.
 

Additional options include:
 

1) System "crt.HandleViewModelInitRequest" on view model initialization.

2) A change request on view model attribute change, more details on this approach below:

! Warning: Theoretically, this approach could cause slower performance when working with the card, as it increases the total number of handler calls (the approach will trigger on every list change: loading, reloading, sorting change, column list change, and column value change).

 

To use this approach, add a change marker to the appropriate DataGrid attribute (example below):


T
hen, add a handler to process the usr.MyRequest in the handlers, similar to how it's done for crt.LoadDataRequest and crt.DataGridCreateItemRequest.
 

As a result, your custom logic will execute when a new column is added, or when a column is deleted, and for other list changes.
 

Hope this helps, and thank you for reaching out!

Hi Pavlo, thank you for the detailed response! I'm sure that functionality will come in handy.

 

Unfortunately, for our use case, we need to perform an action before the data is fetched for the reload, whereas this change triggers only after the data has already been fetched from the database to reload the list. Is there anything that would fire in a similar way but before the data is requested from the server? LoadDataRequest does this, but has the drawbacks of being called only in certain circumstances.

 

Is there any documentation on the event handler "call stack"? This would be really useful, knowing that, for example, when a user clicks the reload button, first handler X is called to do some action, then handler crt.LoadDataRequest is called to handle the outbound data call to the servers, then the data is sent to the user's browser, then handler Y is called to do some action, then handlers that are associated with the change property of viewModelConfig are called when updating the data stored in the List, etc.

 

Many thanks,

Harvey

Harvey Adcock,

Hello,

Thank you for the additional clarification. Unfortunately, at this time, this option is not available.
 

I have created a task for the development team to implement such a handler in the system.
 

Thank you for helping us improve our product.

Best regards,
Pavlo

Hi Pavlo, thanks - I think we really need some more consistency in what triggers handlers and what doesn't. Performance implications of overriding certain handlers is something for the developers to consider (ideally armed with documentation on any things to look out for - the current info on request handlers in the Academy is incredibly limited) and not really something that should be prevented from being done entirely. Why even have the ability to override LoadDataRequest when one of the main times it should be called (first loading data for a List) it doesn't even fire? Developers just end up having to do workarounds that are even worse for performance, such as triggering a reload of the data from code, so the data gets requested twice.

 

There are so many page events which would've previously in Classic UI triggered something in the page code that developers could override as needed, but now it's just flipping a coin to find out if the event you need to capture and handle in some custom way is possible to be overridden or not.

Show all comments

Hello,

 

I need to call a code once a record gets created for the first time. This worked using the following:

handlers: /**SCHEMA_HANDLERS*/[
			{
        request: "crt.SaveRecordRequest",
        handler: async (request, next) => {

 

however what this does is execute the code for each attribute value change, which is not what is needed. How can I call this exactly once just when the record is created for the first time and that's it, without having to call it again for each save request? Thanks

 

Note: I have tried replacing SaveRecordRequest with CreateRecordRequest, however the code was not executed once saving, or on any save.

 

Best,

Mohamad

Like 0

Like

10 comments

You can use the CardState to see if the record is in add mode (record is being added, saved for first time) or edit mode:

const mode = await request.$context.CardMode;
if (mode === “add”) {
    //
}

If you need to call some code exactly once when a record is created, I'd suggest moving the whole logic to backend. Specifically EntityEventListener and implement OnInserting or OnInserted methods to call your logic before or after the record is saved

Ryan Farley,

Hey Ryan,

 

Thanks for the reply, however that didn't work. The CardMode returns undefined, and when inspecting it in developer tools (request.$context object) the value is always 'edit' , when inserting the first time or when updating. Is there anything else I can do to fix the issue? Thanks

 

Best,

Mohamad

Yurii Sokil,

Hey Yurii,

 

Thanks for the reply, I have tried moving the logic to backend, however I encountered some issues. The overloaded method OnInserted cannot be async, and therefore I cannot call APIs directly from that method.

There is another option to call asynchronously using this method https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/back-end-development/objects-business-logic#title-2173-11 . However that doesn't solve the problem as if there were any errors when executing the asynchronous code, the record gets saved normally without indicating errors. Its a fire and forget operation and I need something that prevents a record from being inserted if the API call failed. Is there any way I can achieve this? Thanks for help

 

Best,

Mohamad

Mohamad Salhani,

If all you're after is to set up an auto number column, you can use the new auto number column default value. See https://customerfx.com/article/working-with-autonumber-fields-in-creatio/

Ryan

Ryan Farley,

No, so basically I need to populate a field once a record is created, and the value comes from an external API that I have to call

Ryan Farley,

Thanks for the support, I was finally able to solve it by checking the createdOn and modifiedOn dates for the record and see if they are equal, this way I can identify if the record was added for the first time or not. 

Thanks again!

Hi Mohamad, 
You can use AsyncPump.Run() to call async methods synchronously in your event listener. Also you can override OnInserting rather than OnInserted so your logic is called before the record is actually saved. 

Yurii Sokil,

Hey Yuri,

 

Thanks for the reply! It did work however I have a question. How can I pass arguments to the method passed in AsyncPump.Run() ? 

I have this code, but I can't pass arguments to the method.

 

[EntityEventListener(SchemaName = "UsrPetolTest")]
public class CustomEntityEventListener : BaseEntityEventListener
{
    public override void OnInserting(object sender, EntityBeforeEventArgs e)
    {
        base.OnInserting(sender, e);
 
        var entity = (Entity)sender;
        var userConnection = entity.UserConnection;
 
        AsyncPump.Run(testing);
 
    }
 
    private async void testing()
    {
        try
        {

 

Best,

Mohamad

Show all comments

Hey Community,

I'm looking to access the `onclick` / 'FolderTreeVisibleChanged' handler of the Folders button on Freedom UI list pages. What is the name of the handler method that i can use?


Like 0

Like

3 comments
Best reply

Hello sprity,

If i understood you correctly, you want to control visibility state or togle mode of the folders tree. The handler you provided, well, is responsible for this logic.  

Here is an example of how you can do it:

Toggle mode (open if closed, close if open):

    request: 'crt.FolderTreeVisibleRequest', 
    params: { 
        folderTreeName: "FolderTree_blabla", 
        togglePanel: true 
    } 
}

Explicit visibility mode (always open or always close, regardless of current state):


    request: 'crt.FolderTreeVisibleRequest', 
    params: { 
        folderTreeName: "FolderTree_blabla", 
        visible: true  // or false to close 
    } 
}

As mentioned, this handler also saves the state to the user profile, meaning that when the page is reopened, the folder tree will be in the same state (open or closed) as it was before. If you'd prefer not to save the state in the profile, you can manually update the visibility attribute, like so:

{folder tree name}_visible => FolderTree_blabla_visible

Hope this helps! Let me know if i understood you correctly and if you have any questions let.

Hello sprity,

If i understood you correctly, you want to control visibility state or togle mode of the folders tree. The handler you provided, well, is responsible for this logic.  

Here is an example of how you can do it:

Toggle mode (open if closed, close if open):

    request: 'crt.FolderTreeVisibleRequest', 
    params: { 
        folderTreeName: "FolderTree_blabla", 
        togglePanel: true 
    } 
}

Explicit visibility mode (always open or always close, regardless of current state):


    request: 'crt.FolderTreeVisibleRequest', 
    params: { 
        folderTreeName: "FolderTree_blabla", 
        visible: true  // or false to close 
    } 
}

As mentioned, this handler also saves the state to the user profile, meaning that when the page is reopened, the folder tree will be in the same state (open or closed) as it was before. If you'd prefer not to save the state in the profile, you can manually update the visibility attribute, like so:

{folder tree name}_visible => FolderTree_blabla_visible

Hope this helps! Let me know if i understood you correctly and if you have any questions let.

Yevhenii Grytsiuk,

Thank you for this Yevhenii. One of the more difficult parts of working with Freedom UI is the inability to dig into the out of the box code to see how to change the behavior. This was easy with classic, but for Freedom we have to dig through all the minified code to see if we get lucky finding what we are after. 
Until there's better documentation outlining what all the various requests are to handle, it would be great to have some sort of switch (like the IsDebug setting to enable debug mode) that just dumps all the fired requests to the console (and maybe include what object/component fired the request?) Not sure how reasonable that would be since it's likely quite a bit of stuff would show there, but might make it easier to see the requests that fire when some action is taken.

Ryan

Ryan Farley,

Sounds great to me. I will register your idea so that our r&d team hopefully would implement it.

Show all comments

Hello,

I need to create a custom handler for a button. It is necessary that after the button is clicked, two actions are performed sequentially: first, the record should be saved, and then a process should be triggered. My code isn't working. Could you please help?

 

        handlers: /**SCHEMA_HANDLERS*/[
 {        
     request: "crt.CustomHandler",
     handler: async (request, next) => {
   const result = await next?.handle(request);
   const handlerChain = sdk.HandlerChainService.instance;
   // Спочатку зберігаємо дані
   await handlerChain.process({
       type: 'crt.SaveRecordRequest',
       $context: request.$context,
       dataSourceName: "PDS"
   });
   // Потім викликаємо процес
   await handlerChain.process({
       type: 'crt.RunBusinessProcessRequest',
       $context: request.$context,
       processName: "srProcess_5c65949",
       processRunType: "ForTheSelectedPage",
       showNotification: true,
       recordIdProcessParameterName: "ID"
   });
   return result;
}
}
]/**SCHEMA_HANDLERS*/,
Like 0

Like

2 comments
Best reply

Ігор Роїк,

Hello,

Have you tried importing a "creatio-devkit/common dependecies" as well as passing sdk as a parameter to your schema function? 1

 message: Uncaught Error: Uncaught (in promise): ReferenceError: sdk is not defined
ReferenceError: sdk is not defined

Ігор Роїк,

Hello,

Have you tried importing a "creatio-devkit/common dependecies" as well as passing sdk as a parameter to your schema function? 1

Show all comments