Hi Community,

 

We are trying to create a filter for this detail, that will use two conditions (one for each column) and a logical operator of “OR”. So basically, we only want the records that have the main record id on one of these columns (Contrato or Contrato Umbrella).

 

 

To achieve this, we first tried to add the filter using the FreedomUI Page Designer. However, the filter does not work with the logical operator “OR”.

 

 

So we needed to add it manually, through code. By following this post https://community.creatio.com/questions/detail-filter-freedom-ui. But that didn’t work.

 

 

An alternative was to add the filter in the viewModelConfigDiff section, but we don’t know how can we make the value dynamic.

 

 

Could you please help us find a solution to this problem?

 

Thank you.

Like 3

Like

1 comments

Hello Pedro,

Please review one of the community questions to find the example of Terrasoft.LogicalOperatorType.OR usage.

Additionally here is an explanation of how filtration on Detail work for FreedomUI. 

Case description:
On Contacts page there is a Job experience detail with listed companies where the person worked. Our goal is to show only those departments in the department field that are specified for chosen employer (Account object). So, for this case, Alpha Business has only 2 departments listed in the Departments detail. We only want to see those 2 departments when choosing a department for this account on Job experience detail on Contact page. 

For filtering we basically need just 2 base handlers to be triggered:

  1. crt.DataGridActivateRowBusinessRulesRequest – triggered when we click on an existing detail row or add a new one.
  2. crt.HandleViewModelAttributeChangeRequest – triggered when we change a value of fields.

We also need to create our own handler which we can name usr.ApplyDepartmentFilter. This one would find the currently active row of our detail to have access to its manipulations. After that, we check if account field is filled in and if yes, we create a filter for the Department field. To apply it, we need to use setValue method by targeting filterAttributeName that can be created using the formula: 
"{detailName}DS_{targetFieldName}_List_BusinessRule_Filter".
After that, it is important to use markAsPristine method to make sure that the attribute is applied silently, without forcing us to save the row.

As for crt.DataGridActivateRowBusinessRulesRequest, here we just need to filter it by request.dataGridViewElementName === "CareerList" to target only the detail needed and then call the execution of usr.ApplyDepartmentFilter request that was added earlier.

In crt.HandleViewModelAttributeChangeRequest handler we need to cover the situation when the Employer (Account) field is changed to update the filtration for Department field. First of all, we check if request.attributeName === "CareerList". After that we select the active row and get control over Account field. We check if it’s changed by using account?.dirty property and also if it has value with account?.value?.value, because we would want to filter Department field only in case the Employer is filled in. If those 2 conditions are met, we use markAsPristine method for the account field attribute. We use this one here because it will allow us to handle the subsequent changes of the Employer field. Without it, the field will remain dirty until we save the row. Eventually, we need to set value of the Department field to null using: row?.getAttributeControl(attributeName + "DS_Department").setValue(null, {silent: true});
After that, the usr.ApplyDepartmentFilter handler can be executed to apply the filtration of Department field by Employer.

Show all comments

Hi community,

Calling a Business process is quite easy in FreedomUI, by adding a button and choosing

Action: Run process.

The problem with this approach is that once the button is clicked, there is no validation happening in the page.

Is there any code snippet or workaround that when clicking a button that runs a business process, prior to the calling of the process a validation(practically a Save) happens?

Sasori

Like 1

Like

6 comments

The only option currently is to wire up code for the button. It would first save the page, then if the save was successful you would execute the process. 

See how to save the page and detect if it was successful here: https://customerfx.com/article/saving-a-page-before-some-action-on-a-creatio-freedom-ui-page/

See how to start the process via code here: https://customerfx.com/article/starting-a-process-from-client-side-code-on-a-creatio-freedom-ui-page/

Ryan

Ryan Farley,

Thanks for the response Ryan. Do you actually have an example on how to integrate within the 'CustomMethod' both crt.SaveRecordRequest and crt.RunBusinessProcessRequest ?

Ryan Farley,

Ryan if im not mistaken, with the suggested approach , every time the user will click the SAVE button, the overriden crt.SaveRecordRequest will be called?

In the first linked example, you would only be running that `usr.CustomCodeRequest` handler when you click your custom button. If you put the code inside the crt.SaveRecordRequest handler, then it would be run every time the user saved the page in some way.

Sasori Oshigaki,

As Harvey mentioned, the code for your button will only execute when the button is clicked, not when the Save is clicked. Your button will also initiate a save and then, if successful and validated (and the save occurred) it will then execute the process. The code from the first article triggers the save to happen and then provides the result. In the article (the first one) the save returns a result, where the code has // save was successful, continue with something else here you'd replace that with the code to start the process (the second article). If needed, you can see how to wire up custom code to your button in this article: https://customerfx.com/article/adding-a-button-to-execute-custom-code-on-a-creatio-freedom-ui-page/

Ryan

Thank you  both Ryan and Harvey! Was able to achieve what i intended!

     {
    request: "so.SaveAndRunBP",
    handler: async (request, next) => {
            const saveRecordRequest = {
            type: "crt.SaveRecordRequest",
            preventCardClose: true,
            $context: request.$context
        };
        if ((await request.$context.executeRequest(saveRecordRequest)))
        {
          const handlerChain = sdk.HandlerChainService.instance;
          const result = await handlerChain.process({
              type: "crt.RunBusinessProcessRequest",
              processName: "SoGenerateContact",
              processParameters: {
                  ContactId: await request.$context.Id,
              },
              $context: request.$context
          });
        }
        return next?.handle(request);
    }
}
Show all comments

I have a detail "OrderProductDetailV2" (editable registry), in which I added my totals to "summaryItemsContainer". When changing a record in the detail, quantity, price, etc., I need to update my signatures, since the standard ones are updated (number of records, total amount). I've read many articles. I've figured out how the standard modules work. Everything is clear. I've tried different options through messages, with "onDataChanged" I get a cycle, in another option my signatures are updated, but the standard ones stop updating. Can anyone help?

Like 0

Like

1 comments

Hello,

The base logic of updating Amount and Total columns is mostly located inside the event logic of objects OrderProduct and Order. You can add your logic of updating fields using the same event logic or business process. There is definitely a risk of ending up in a loop, unfortunately, there are no recommendations to avoid it, you just need to pay attention to your code. But, because the base update is handled in event logic, you can update your values without triggering the event logic, for example with direct DB request or class Update. 

Show all comments

Hi!

I want to add a button to a detail page with a Data Import action, using the crt.ImportDataRequest action.
I need to specify a default value (the id of the current detail) to a field. Can I do that? Does anybody knows the entire list of parameters for this action?

Thank you in advance,

Ignacio Alvarez

Like 2

Like

3 comments
Best reply

Hello Ignacio,

 

Currently, the system is designed in a way that it is not possible to pass custom parameters into the params object of the crt.ImportDataRequest request. But we've created a request for our R&D team to make it possible to do and implement it in one of the next application releases. Thank you for this idea and for helping us in making the app better!

Hello Ignacio,

 

Currently, the system is designed in a way that it is not possible to pass custom parameters into the params object of the crt.ImportDataRequest request. But we've created a request for our R&D team to make it possible to do and implement it in one of the next application releases. Thank you for this idea and for helping us in making the app better!

I fully support Ignacio's request as the import feature really needs some love.

Common requests include importing the same value in multiple columns, transforming values with regular expressions, importing data into various fields in related tables, importing from sources like FTP, cloud storage, and creatio file storage, locking the addition of lookup values, and quite some more!

 

BR,

Robert

+++

Show all comments

Is it possible to specify mask IDs when showing & hiding body masks while data loads? I'm asking as it seems like my body mask is being hidden by some other process before the process I want the mask to show for has completed, so it grants the user the ability to control the page before it's ready.

 

What I was thinking is that if the body mask was given some ID when shown using showBodyMask, only a hideBodyMask specifying that same ID would hide the body mask - any others doing the same may make their own body mask hidden, but if any of them still remained, you would still see the loading spinner. For some reason I seem to remember this being possible in Classic UI, but I can't remember exactly or find the examples.

Like 0

Like

3 comments
Best reply

It was possible to get the mask Id in classic (it is returned from MaskHelper.ShowBodyMask()), but I don't believe that had any impact on something else not hiding the mask. As far as I am aware, that was only used to get the mask so you could display or change the message (the Freedom UI mask doesn't have a message, only the spinner)

It was possible to get the mask Id in classic (it is returned from MaskHelper.ShowBodyMask()), but I don't believe that had any impact on something else not hiding the mask. As far as I am aware, that was only used to get the mask so you could display or change the message (the Freedom UI mask doesn't have a message, only the spinner)

Makes sense, must have been mis-remembering then, cheers Ryan. Would be nice to be able to show & hide specific body masks, as sometimes there will be multiple sets of data loading in in parallel, with no guarantees of which will finish first/last.

Hello,
Your idea has been registered to our R&D team, thank you for providing us with new ways to improve.

Show all comments

Dear colleagues,

 

I have a problem when deleting records in a detail, when the deletion is one by one we can manage it, but when the user selects several records and deletes them, the deleted record trigger is not activated.

 

  1. How can this kind of massive deletion event be detected?
  2. Is it possible to remove from the detail menu the option to select multiple records?

 

Thanks in advance

Like 1

Like

4 comments
Best reply

Julio.Falcon_Nodos,


Hello,
 

The button is added in the addGridOperationsMenuItems method of the BaseGridDetailV2 schema, depending on the value of getSwitchGridModeMenuItem.


To remove the button, simply override this method in the desired detail with the following value:


methods: {
   getSwitchGridModeMenuItem: function() {
       return false;
   },
}
 





However, it’s important to note that removing the button does not disable the ability to select multiple records, for example, using the "Ctrl + Click" combination. Unfortunately, disabling multi-selection entirely is not possible for Classic UI details.

Best regards,
Pavlo

Hello,
 

Creatio does not have a separate event for multi-delete event; each delete operation will be processed separately.
 

I was unable to reproduce the behavior where logic tied to the deletion event of records fails to execute in case of multi deletion.

 Could you please provide more details about your mechanism's configuration?
 

Regarding the possibility of removing multi-select in a detail, in Freedom UI, you can configure this in the page designer by unchecking the "Multiselect" parameter. 


Unfortunately, this is not possible in Classic UI.
 

Best regards,
Pavlo!

Pavlo Sokil,

Thanks Pablo, of course is for a classic ui detail..

 

I think it's possible to solve, you can see some approach on the last comment in the article on https://community.creatio.com/questions/hide-delete-button-condition

 

The problem is there not enough documentation, but I think I'm on right way, at this time didn't know how to continue to hide, from the detail menu, the select all records option.

 

Regarding to detect, in a process a massive delete, no idea if it's possible :-(

Julio.Falcon_Nodos,


Hello,
 

The button is added in the addGridOperationsMenuItems method of the BaseGridDetailV2 schema, depending on the value of getSwitchGridModeMenuItem.


To remove the button, simply override this method in the desired detail with the following value:


methods: {
   getSwitchGridModeMenuItem: function() {
       return false;
   },
}
 





However, it’s important to note that removing the button does not disable the ability to select multiple records, for example, using the "Ctrl + Click" combination. Unfortunately, disabling multi-selection entirely is not possible for Classic UI details.

Best regards,
Pavlo

Thanks Pavlo! it works

Show all comments

Is it possible to override an OOTB C#-defined REST endpoint in Creatio? In our case, we need to trigger some action when a file is uploaded, and since the file record creation doesn't trigger business processes/similar, we need to do this some other way. One option we are trying to attempt is overriding the FileApiService's UploadFile method to trigger the behaviour after calling the base class to behave as normal for the file upload, but we can't seem to get any override behaviour of the WCF method to work. Does anybody have information or an example of how this might be done, or some other option that we could pursue?

Like 0

Like

1 comments

Hello Harvey,

Overriding the base REST service seems to be impossible in our system. We attempted to do this but were unsuccessful. I suggest creating a business process that starts after a specified delay (for example, one hour) to perform the required actions after the file upload. 

Show all comments


Hello Creatio Community,

 

I'm working on integrating Creatio CRM with a third-party application, and I’d like users to access specific Creatio pages without needing to log in each time they navigate from the third-party app.


Here are some specifics of my setup:
When users are logged into the third-party app, they should be able to open Creatio pages directly without being redirected to the login page.

 

I’m using URLs with ?autoOpenIdLogin=true to facilitate automatic login.

 

My main questions are:
Are there recommended ways to keep the SSO session active between the two apps?
Has anyone implemented a solution using silent authentication checks or embedded iframes to keep the session refreshed?


Any insights or best practices would be appreciated!

 

Regards,

Ajay K

Like 1

Like

1 comments

Hello,
 

Could you please provide more technical details regarding your implementation? Are you using OpenID for authentication in Creatio? What specific issues have you encountered with your current setup when using ?autoOpenIdLogin=true in the link?

Have you considered an integration option through SSO with an automatic redirect setup? This would ensure that if the user is already authenticated on the IdP side, they will be automatically redirected back and logged into Creatio. 

With this setup, the user will be redirected to the IdP, logged in automatically if in current session he is logged in on Identity provider side, and then redirected back to the record page without login page.
 

(Steps for achieving this are outlined in the following article: SSO setup guide.

Please note that Step 5 – “Set SSO as the default option” is essential. The rest of the SSO setup instructions should be followed according to the latest version in the Creatio interface.)
 

If you’re using a cloud environment, please inform the support team of the need to enable auto-redirect.
 

We recommend testing this approach, and we hope it will be helpful!

Show all comments

I am trying to get contact collection data from creatio using OData 4. 

 

In my account, I have tons of contact data, but somehow API gives empty error.

 

Is it something related to permission access related issue?

 

 

@Community, please help to solve this issue

Like 0

Like

1 comments
Best reply

Hello. Make sure that the user used to authenticate the request has the right to read the data of the "Contact" Object. Check in the System Designer, Access Rights to Objects.

Hello. Make sure that the user used to authenticate the request has the right to read the data of the "Contact" Object. Check in the System Designer, Access Rights to Objects.

Show all comments

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