Is it possible to intercept using some request handler the event when a user clicks on the green "Complete" button on a Next Steps tile? This is the button in the "next-step-tile-actions" div on the page which only appears when you hover over the next step tile:

 

It would be vey helpful to be able to run some custom code when this button is clicked - in our case, we need it to save the main page record before actioning this next step, as completing the next step might automatically transition the Lead to the next stage, losing any data entered by the user.

Like 220

Like

6 comments

None of the following handlers are triggered by clicking this button, maybe I've missed some candidates but these are the ones I've tried so far:

crt.ChangeNextStepsStateRequest

crt.OpenPageRequest

crt.UpdateRecordRequest

crt.CreateRecordRequest

Also tried "brute forcing" it by overriding every handler I could find in the Creatio code, but literally nothing fires when clicking that button! Not even something like the page's crt.HandleViewModelPauseRequest (since it's a modal popup, I guess the full page doesn't actually pause like it would when navigating to a another page through clicking a lookup for example). Hopefully I've missed something, triggering some action on clicking that button would be useful.

Any thoughts/knowledge on how such a thing could be achieved?

Hi Harvey! 

 

Unfortunately, at the moment, there is no way to intercept the event of clicking on the Next-steps tile buttons. This button can call different requests depending on the type of tile, and these requests are called without the view model context, which will not allow us to intercept them from the card and use them to save card data.

 

We have registered your idea, and the R&D team has already planned the task for this improvement - they will create a special output event for the Next-steps component. This functionality will be available in future releases.

 

Thank you for making our product better!

 

Best regards,

Natalia

Thank you for the information Natalia, this would be a welcome improvement!

Hi Natalia, is there any expected timeline for this improvement known yet? Do you have a reference for the planned task for later follow-up?

Show all comments

Just a quick PSA - either 8.1.2 or 8.1.3 breaks the ability we had before of being able to set Page Parameter values in the crt.HandleViewModelInitRequest request handler, since in the newer versions it appears the value is reset back to the default (similar to how fields based over table columns are) at some time after the init handler runs. This is quite frustrating, as it's reducing the number of options we have for setting values in the code where required (which it still often is with the current options for no code development).

 

A workaround that Ryan Farley has previous mentioned using for setting field values by using a javascript timeout can be used for this too, e.g.

setTimeout(() => {request.$context.TextPageParameter = "Test value";}, 300);
Like 2

Like

8 comments

Hello, Harvey

I also had such an isuue but I resolved it by calling parameter initialization after let result =  await next?.handle(request); And then in the end return result; 

Andrii Orlenko,

 

Mine was already being initialised after awaiting the result of handling the request, so it might be that sometimes this takes long enough to be ok but not always (so would introduce a race condition).

Harvey Adcock,

Thank you for the provided information!
The problem is already registered on the R&D team, and we hope to see the fix in future releases.

Anhelina,

Thank you. 

Just an FYI, I've been reporting this since 8.0.10 (see #SR-01234445). I was told this would be resolved in "the nearest releases (8.1.1-8.1.2)", however, it's still an issue in 8.1.3 without a commitment from Creatio on a specific timeframe for a resolution. This is a pretty huge pain point so it's disappointing that it's still a problem. I do love Freedom UI (and I'll take it any day over classic!) but there's been many instances of my code breaking along the way with new versions and it sometimes seems less urgent for fixes for issues that go beyond the "no code" customizations.

Ryan

Ryan Farley,

I checked that case before replying to Harvey and asked the responsible team to raise the priority for this task. I apologize for the delay and hope to see the fix soon.
Meanwhile, they shared one more workaround, which is better to use with parameters:

add the handler on parameter changing and rewrite it when the default value has appeared:

Example

Anhelina,

Yes, this approach does work if all you need when the form is initialized is to work with a single value on the page. However, that is often not the case and each property initialization can happen at slightly different times, so referencing other attributes in this same handler might not work, depending on the timing of the various attributes being loaded/initialized. Adding a separate handler for each attribute you need to work with can get messy quick.

Ryan

What I think would be nice/match the existing patterns would be to have some new request handler that does the setting of default values on the page, something like "crt.HandleAttributeInitRequest", which would perform the OOTB platform's setting of these values in the next?.handle(request) and then after awaiting the result of that a developer could set their own defaults for fields they need to, which wouldn't be overwritten (since the defaults had already been set).

 

It would also be nice to be able to "silently" set these default values (like you could in Classic UI) so that setting values in that request handler wouldn't cause the "are you sure" dialog to appear if a user closes the page without actually modifying the data themselves. Actually it would be nice to be able to do that generally from within request handler code.

Hi, is there any update on the matter? 
Still when you're trying to read the attributes on crt.HandleViewModelInitRequest the attributes aren't initialized and are all undefined

Show all comments

It looks like in 8.1.3, when clicking the magnifying glass on a lookup field which is configured to show the lookup page modal popup, the handler crt.OpenSelectionWindowRequest is now called instead of crt.OpenLookupPageRequest. Is is the case that the old handler has been swapped for the new one? Why has this been done? And are there any important differences to be noted? It's broken some of our client's custom code in the upgrade, and from a surface view it looks like it works in much the same way as the old handler and that simply swapping the code to use the new handler instead of the old works, but don't want to make any assumptions on that. Anybody have any insight on this?

Like 2

Like

10 comments

Hmm. Good find. I’ll have some broken customizations as well. Hopefully we’ll get an official word about the change. This isn’t the first time I’ve had things break from changes to core Freedom UI things. I like using Freedom UI but at times it feels like a moving target. We need some commitment from Creatio about avoiding breaking changes. 
Ryan

Hi Harvey, 

I just tested this in an 8.1.3.6734 system and both "crt.OpenSelectionWindowRequest" and "crt.OpenLookupPageRequest" did open the selection/lookup window for me. However, using the results seemed to work differently depending on which request I used, it didn't work to just change the request name and leave the rest of the code as-is. So they do appear to possibly be slightly different requests, at least from my very limited tests so far 🤷🏼‍♂️

Ryan

Interesting, thanks for the additional info Ryan! For triggering the lookup page from code I think we'll stick with the original method for now then.

 

But a little PSA for anyone wondering why their code overriding the crt.OpenLookupPageRequest handler to intercept and add filters/perform other logic when a user triggers a lookup page on a lookup field configured to view as "Selection window" rather than dropdown list, they should now be overriding crt.OpenSelectionWindowRequest instead. Hopefully we'll get some clarification on why this has changed and any implications.

Harvey Adcock,

8.1.3 is the first release with this API published, and Creatio mentioned the API for Freedom UI selection window in the 8.1.3 release notes. At the same time, we left it without changes so as not to break possible customizations with the old unpublished API. However, the old API is effectively deprecated, and the new API should be used from now on.

The full article for the Academy is almost ready and will be officially published soon.
Here is part of main information (maybe some parts will be changed, that's why please follow the updates): 
In order to open the lookup window, you have to use crt.OpenSelectionWindowRequest:
 

/**
 * @publicApi
 */
@CrtRequest({
    type: 'crt.OpenSelectionWindowRequest',
})
export class OpenSelectionWindowRequest extends BaseRequest {
    public itemAttributeName?: string;
    public itemsAttributeName?: string;
    /**
     * @publicApi
     */
    public entitySchemaName?: string;
    /**
     * @publicApi
     */
    public schemaName?: string;
    /**
     * @publicApi
     */
    public filtersConfig?: FiltersConfig;
    /**
     * @publicApi
     */
    public features?: PageLookupFeatures;
    /**
     * @publicApi
     */
    public selectionState?: SelectionState;
    /**
     * @publicApi
     */
    public afterClosed?: (result: SelectionWindowResult) => void;
    /**
     * @publicApi
     */
    public caption?: LocalizableString;
}

 

Add the following code to your custom handler:

handlers: /**SCHEMA_HANDLERS*/[
			{
				request: "usr.OpenLookupRequest",
				handler: async (request, next) => {
					devkit.HandlerChainService.instance.process({
						type: "crt.OpenSelectionWindowRequest",
						scopes: [...request.scopes],
						$context: request.$context,
						entitySchemaName: "Contact",
						// caption: 'Responsible',
						schemaName: 'CustomLookupPage',
						itemAttributeName: 'LookupAttribute_2mnilrq',
						// itemsAttributeName: 'Contact_List',
						afterClosed: async (result) => {
							if (!result.canceled) {
								const lookupValues = await result.getLookupValues();
								const value = lookupValues[0];
								if (value) {
									alert(value?.displayValue ?? '');
								}
							}
						},
						filtersConfig: {
							filterAttributes: [
								{
									name: 'MyFilter',
									loadOnChange: false
								}
							],
							attributesConfig: {
								MyFilter: {
									value: {
										"items": {
											"29e16d42-36f1-4e04-9029-4321cbb2494d": {
												"filterType": 1,
												"comparisonType": 11,
												"isEnabled": true,
												"trimDateTimeParameterToDate": false,
												"leftExpression": {
													"expressionType": 0,
													"columnPath": "Name"
												},
												"isAggregative": false,
												"dataValueType": 1,
												"rightExpression": {
													"expressionType": 2,
													"parameter": {
														"dataValueType": 1,
														"value": "Super"
													}
												}
											}
										},
										"logicalOperation": 0,
										"isEnabled": true,
										"filterType": 6,
										"rootSchemaName": "Contact"
									}
								}
							}
						}
					});
					return next?.handle(request);
				}
			}
		]/**SCHEMA_HANDLERS*/,

where

entitySchemaName - the name of the entity schema whose data is displayed in the lookup window. Optional parameter. If not specified, the data source is taken from the attribute specified in itemAttributeName

caption - optional parameter, displayed in the window title. If caption is not specified, the caption is taken from the attribute specified in the itemAttributeName parameter. If itemAttributeName is not specified, then from the entity schema.

schemaName - the name of the schema that is displayed in the lookup window. Optional parameter. Default is BaseLookupPageTemplate

itemAttributeName - the name of the attribute from which the title is taken, the name of the entity schema and in which the result of the selection in the window will be written. Optional parameter. As a rule, this is the attribute with which the Combobox control is associated.

itemsAttributeName - the name of the attribute from which the data source name is taken. Optional parameter.

afterClosed - callback function returning the result of the selection in the window. Optional parameter.

filtersConfig- describes the filter to be applied to the data. Optional parameter

P.S. Additionally, users can enable features and much more, which you're able to read from the article on the Academy in the near future.

 

Anhelina,

Thanks for this Anhelina. 

Anhelina, 

Hi!

How i can filter SelectionWindow by using value from lookup field on page? 

 

I try this: 

{
   request: "usr.AddSection",
   handler: async (request, next) => {
 
       const id = request.$context.PDS_Transport2_93i8xm8;
 
 
       request.$context.executeRequest({
           type: "crt.OpenLookupPageRequest",
           $context: request.$context,
           entitySchemaName: "Section",
           features: {
               select: {
                   multiple: true,
                   selectAll: false,
                   resultType: 'lookupValues'
               },
               create: {
                   enabled: false
               }
           },
           filtersConfig: {
               filterAttributes: [
                   {
                       name: 'MyFilter',
                       loadOnChange: false
                   }
               ],
               attributesConfig: {
                   MyFilter: {
                       value: {
                           "items": {
                               "29e16d42-36f1-4e04-9029-4321cbb2494d": {
                                   "filterType": 1,
                                   "comparisonType": 11,
                                   "isEnabled": true,
                                   "trimDateTimeParameterToDate": false,
                                   "leftExpression": {
                                       "expressionType": 0,
                                       "columnPath": "Transport"
                                   },
                                   "isAggregative": false,
                                   "dataValueType": 1,
                                   "rightExpression": {
                                       "expressionType": 2,
                                       "parameter": {
                                           "dataValueType": 1,
                                           "value": id.value
                                       }
                                   }
                               }
                           },
                           "logicalOperation": 0,
                           "isEnabled": true,
                           "filterType": 6,
                           "rootSchemaName": "Section"
                       }
                   }
               }
           },
           afterClosed: function(selectedItems) {
               const textValues = Object.values(selectedItems).map(item => item.displayValue).join(', ');
               request.$context.PDS_SectionUpload_h11bk0p = textValues;
           }
       });
   }
}

but always get error: The data types nvarchar and uniqueidentifier are incompatible in the add operator.

Ryan Farley,

Maybe you can help?

 

Grygorii Synieok,

You forgot to await the value when getting the attribute. 

Change to this (note the added "await"): 

const id = await request.$context.PDS_Transport2_93i8xm8;

Ryan

Ryan Farley,

Thank you!

But another problem was with: "dataValueType":10 and  "comparisonType":3 with this parametrs works fine.

Full code:

{
    request: "usr.AddSection",
    handler: async (request, next) => {
 
        var autoId = await request.$context.PDS_UsrTransport2;
 
 
        request.$context.executeRequest({
            type: "crt.OpenLookupPageRequest",
            $context: request.$context,
            entitySchemaName: "SectionAuto",
            features: {
                select: {
                    multiple: true,
                    selectAll: false,
                    resultType: 'lookupValues'
                },
                create: {
                    enabled: false
                }
            },
            filtersConfig: {
                filterAttributes: [
                    {
                        name: 'MyFilter',
                        loadOnChange: false
                    }
                ],
                attributesConfig: {
                    MyFilter: {
                        value: {
                            "items": {
                                "29e16d42-36f1-4e04-9029-4321cbb2494d": {
                                    "filterType": 1,
                                    "comparisonType":3,
                                    "isEnabled": true,
                                    "trimDateTimeParameterToDate": false,
                                    "leftExpression": {
                                        "expressionType": 0,
                                        "columnPath": "Transport"
                                    },
                                    "isAggregative": false,
                                    //"dataValueType": 1,
                                    "rightExpression": {
                                        "expressionType": 2,
                                        "parameter": {
                                            "dataValueType": 10,
                                            "value":autoId.value
                                        }
                                    }
                                }
                            },
                            "logicalOperation": 0,
                            "isEnabled": true,
                            "filterType": 6,
                            "rootSchemaName": "SectionAuto"
                        }
                    }
                }
            },
            afterClosed: function(selectedItems) {
                const textValues = Object.values(selectedItems).map(item => item.displayValue).join(', ');
                request.$context.PDS_UsrSection = textValues;
            }
        });
    }
}

Hello Harvey,

 

I've a 8.1.3 environment and on some pages the crt.OpenLookupPageRequest works correctly  while on other pages it doesn't open the required lookup

Do you have the same issue ?

 

 

 

 

 

Show all comments

Hi,

 

I have a Freedom UI list where I can take a few actions after the user has selected one or more rows. The actions run as expected, but the records are kept selected after the actions run and the user has to manually clear the selection. What do I need to add to the custom code to clear the selection? 

Thanks,
Jose 

File attachments
Like 1

Like

7 comments
Best reply

Jose Hernandez,

 

You need to try

 

request.$context.GridDetail_tviz7gf_SelectionState = null
 

null is needed to remove the selection, but also change GridDetail_tviz7gf to your list attribute.

Hello,

Could you describe exactly what your custom logic performs for better understanding?

Malika,

 

It depends on the action. The Unlock one just clears the locked by field for the selected cases. The print generates letters and sends them to our print vendor for each case selected. Finally, the Assign one opens a window where the user can select the person to assign the cases to. Each one is calling the code below with the proper parameters.

I just need to know what I need to add to that code to clear the selection after the code that runs the business process.

 

Thanks,

Jose

        processSelectedRows: async function(request, processName, message, next) {
            var selectedRecords = await this.getSelectedRows(request.$context);
            var count = selectedRecords.count;
            var date = new Date();
            var hours = date.getHours();
            var minutes = date.getMinutes();
            var ampm = hours >= 12 ? 'PM' : 'AM';
            hours = hours > 12 ? hours - 12 : hours;
            var timeString = hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0') + " " + ampm;
            message = message + " on " + timeString + " for " +  count + " selected records.";
            request.$context.executeRequest({
                type: "crt.NotificationRequest",
                message:message
            });
            const handlerChain = sdk.HandlerChainService.instance;
            result = await handlerChain.process({
                type: 'crt.RunBusinessProcessRequest',
                processName: processName,
                processRunType: "RegardlessOfThePage",
                processParameters: {
                    "SelectedRecords": selectedRecords.selected
                },
                $context: request.$context
            });
            if (!result.success)  {
                var errorMsg = Ext.String.format(resources.localizableStrings.UnableToProcessSelectedRows, processName, result.errorInfo?.message);
                request.$context.executeRequest({
                    type: "crt.NotificationRequest",
                    message: errorMsg
                });                        
            }
            /* Call the next handler if it exists and return its result. */
            return next?.handle(request);
        }

I've not tried clearing the selections, but it might work to do this after you execute the process: 

request.$context.DataTable_SelectionState.selected = [];

Or it could be that you'll set SelectionState to null or {}?

Ryan

Ryan Farley,

Thanks Ryan. I tried that (and other variations like setting the type to 'clear') and the model gets cleared, but the GUI is not refreshed. In other worlds on the page the records are still showing as selected even though the model now has cleared the selection.

Jose Hernandez,

 

You need to try

 

request.$context.GridDetail_tviz7gf_SelectionState = null
 

null is needed to remove the selection, but also change GridDetail_tviz7gf to your list attribute.

Thanks Oleg. That worked. In my case I used  request.$context.DataTable_SelectionState = null; 

Viktoriia,

 

Hello,

 

It's 

 

request.$context.DataTable_SelectedRows
 

DataTable should be replaced with your list attribute name.

Show all comments

HI, 

 

How do I push or replace navigation history in freedom. In classic UI you were able to do it  using a sandbox message. 

 

Is it possible to be done in Freedom?

 

Thank you!

Like 1

Like

4 comments

Are you referring to pushing to navigation history (as far as going to the record/page itself)?

If so, this shows how to open a page (section or other page) https://customerfx.com/article/navigating-to-a-page-via-code-in-a-creatio-freedom-ui-page/

This shows how to open a record page in add or edit mode https://customerfx.com/article/opening-an-edit-page-to-add-or-edit-a-record-via-code-in-a-creatio-freedom-ui-page/

If I've misunderstood what you're after let me know. Hope this helps. 

Ryan

Hi Ryan, thank you for your answer.

No that's not what I'l looking for. What I want to do is what history.replaceState(state, unused, url) does in JS. change the shown url and the browser history, but not navigate. 

Javier Collazo,

Ah I see now. I've not noticed any equivalent of that in the devkit. I've seen a navigationservice and router classes as possibilities in the internal code, but they aren't exposed in devkit.

One possibility is to use the "crt.7XRequest" request. I've been able to use that for what would have been a sandbox.publish previously, a least for what I've tried with it so far. See https://customerfx.com/article/navigating-a-user-back-from-a-creatio-freedom-ui-page/

Might take a little playing with to figure out how to get the other params passed for stateObj, pageTitle, etc. Searching the source for "crt.7XRequest" would likely find some examples of similar requests.

Ryan

Javier Collazo,

I did find an example: 

await handlerChain.process({
    type: "crt.7XRequest",
    $context: null,
    action: "ReplaceHistoryState",
    hash: someHash,
    stateObj: obj,
    silent: isSilent
});

Ryan

Show all comments

Hello.

I have a freedom UI FormPage, which may be opened from Business process (Open edit page element). I want to override Cancel button handler in such way that to cancel current business process. I need to know process id (SysProcessLog table) or process element id (SysProcessElementLog table). How could I obtain them in Freedom UI? For example in Classic UI edit page there was dedicated attribute called ProcessData. I looked through request.$context and didn't find anything similar.

 

Creatio version is 8.1.2

Like 0

Like

2 comments

Hello!

 

To find information, you can read the data from SysProcessData, more information which contains the interrelationship between the process instance and the subprocess, the relationship to the process scheme, the relationship to the process scheme element if the instance is a subprocess, and the current status of the process instance. Also, the internal state of the process is a snapshot of the values of the parameters at times when the process elements are executed.

 

Also, this article could be useful:

https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/development-tools/external-ides/examples/develop-c-sharp-code-in-a-custom-project

 

Kyrylo Atamanenko,

Thanks for an answer. But to read all those information I need to know Id of an element being executed. For example in Classic UI it is obtained like 

this. 

const processElementUId = this.get("ProcessData").procElUId;

And the question is there analogue in Freeom UI page?

Show all comments

Hi there. 

The goal is to adjust visibility of row toolbar Item depending on the value of the field of corresponding record. I added necessary column (ClvSaleStatus) to the list in Freedom UI designer, so all the changes to viewConfigDiff, viewModelConfigDiff and modelConfigDiff look to be present. But nevertheless, If i hide that column manually in the list page then corresponding attribute has undefined value and toolbar item is not visible

viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
	{
		"operation": "merge",
		"name": "DataTable",
		"values": {
			"columns": [
				...
				{
					"id": "791d9bca-eac2-a585-0b1f-8ebacf4e2fa4",
					"code": "PDS_ClvSaleStatus",
					"path": "ClvSaleStatus",
					"caption": "#ResourceString(PDS_ClvSaleStatus)#",
					"dataValueType": 10,
					"referenceSchemaName": "ClvSaleStatus"
				}
			],
			"rowToolbarItems": [
				...
				{
					"type": "crt.MenuItem",
					"caption": "#ResourceString(ReserveObjectMenuItemCaption)#",
					"icon": "open-button-icon",
					"disabled": "$Items.PrimaryModelMode | crt.IsEqual : 'create'",
					"visible": "$Items.PDS_ClvSaleStatus | clv.IsObjectForSaleConverter",
					"clicked": {
						"request": "crt.ClvReserveObjectRequest",
						"params": {
							"itemsAttributeName": "Items",
							"recordId": "$Items.PDS_Id"
						}
					}
				}
			]
		}
	}
...
]/**SCHEMA_VIEW_CONFIG_DIFF*/
viewModelConfigDiff: /**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/[
	...
	{
		"operation": "merge",
		"path": [
			"attributes",
			"Items",
			"viewModelConfig",
			"attributes"
		],
		"values": {
			...
			"PDS_ClvSaleStatus": {
				"modelConfig": {
					"path": "PDS.ClvSaleStatus"
				}
			}
		}
	},
]/**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/
modelConfigDiff: /**SCHEMA_MODEL_CONFIG_DIFF*/[
	{
		"operation": "merge",
		"path": [
			"dataSources",
			"PDS",
			"config"
		],
		"values": {
			"entitySchemaName": "ClvObject",
			"attributes": {
				...
				"ClvSaleStatus": {
					"path": "ClvSaleStatus"
				}
			}
		}
	}
]/**SCHEMA_MODEL_CONFIG_DIFF*/,
converters: /**SCHEMA_CONVERTERS*/{
	"clv.IsObjectForSaleConverter": function(value) {
		const result = value?.value == ClvJsConsts.ClvSaleStatus.ForSale;
		return result;
	}
}/**SCHEMA_CONVERTERS*/,
Like 0

Like

4 comments

Hi, here is an example of how to get the column value:

viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
			{
				"operation": "insert",
				"name": "DataGrid_3c1xo0k",
				"values": {
					----
					"columns": [
						------
						{
							"id": "a68e978a-790d-9af6-974e-c102ee0bd00e",
							"code": "DataGrid_3c1xo0kDS_Stage",
							"path": "Stage",
							"caption": "#ResourceString(DataGrid_3c1xo0kDS_Stage)#",
							"dataValueType": 10,
							"referenceSchemaName": "OpportunityStage"
						}
					],
					"rowToolbarItems": [
						{
							"type": "crt.MenuItem",
							"caption": "Test",
							"icon": "open-button-icon",
							"disabled": false,
							"visible": "$DataGrid_3c1xo0k.DataGrid_3c1xo0kDS_Stage | clv.IsObjectForSaleConverter",
							------
			},
-----
		]/**SCHEMA_VIEW_CONFIG_DIFF*/,
		viewModelConfigDiff: /**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/[
			{
				"operation": "merge",
				"path": [
					"attributes"
				],
				"values": {
					-----
					"DataGrid_3c1xo0k": {
						"isCollection": true,
						"modelConfig": {
							"path": "DataGrid_3c1xo0kDS"
						},
						"viewModelConfig": {
							"attributes": {
								"DataGrid_3c1xo0kDS_Title": {
									"modelConfig": {
										"path": "DataGrid_3c1xo0kDS.Title"
									}
								},
								"DataGrid_3c1xo0kDS_Stage": {
									"modelConfig": {
										"path": "DataGrid_3c1xo0kDS.Stage"
									}
								},
-----
					}
				}
			}
		]/**SCHEMA_VIEW_MODEL_CONFIG_DIFF*/,
		modelConfigDiff: /**SCHEMA_MODEL_CONFIG_DIFF*/[
			----
		]/**SCHEMA_MODEL_CONFIG_DIFF*/,
		handlers: /**SCHEMA_HANDLERS*/[]/**SCHEMA_HANDLERS*/,
		converters: /**SCHEMA_CONVERTERS*/{
			"clv.IsObjectForSaleConverter": function(value) {
				const result = value?.value == "test";
				return result;
			}
		}

Dmytro Vovchenko,

Well I didn't see any difference to mine code except that you are probably making it for detail and thus inserting new collection attribute "DataGrid_3c1xo0k" while my code is for section and thus merges new attribute to some collection attribute called "Items" which is added in BaseGridSectionTemplate schema.

Anyway, I solved my task by jsut making "clv.IsObjectForSaleConverter" async and requesting column value from db if it's hidden from the list

converters: /**SCHEMA_CONVERTERS*/{
	"clv.IsObjectForSaleConverter": async function(value, scope) {
		let result = value?.value == ClvJsConsts.ClvSaleStatus.ForSale;
		if (!result && !value) {
			const currentRecId = await scope.PDS_Id;
			if(sdk.isGuid(currentRecId)) {
					  const dataModel = await sdk.Model.create("ClvObject");
 
					  const filters = new sdk.FilterGroup();
 
					  filters.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "Id", currentRecId);
 
					  const records = await dataModel.load({
						  attributes: ["Id", "ClvSaleStatus"],
						  parameters: [{
							  type: sdk.ModelParameterType.Filter,
							  value: filters
						  }
				]
					  });
					  const firstRecord = records[0];
					  const recSaleStatusId = firstRecord?.ClvSaleStatus?.value;
					  result = recSaleStatusId == ClvJsConsts.ClvSaleStatus.ForSale;
			}
		}
		return result;
	}
}/**SCHEMA_CONVERTERS*/,

 

Dmytro Vovchenko,

Ok, I rewrote viewModelConfigDiff to exactly match yours

{
	"operation": "merge",
	"path": [
		"attributes",
	],
	"values": {
		"Items": {
			"viewModelConfig": {
				"attributes": {
 
					"PDS_ClvSaleStatus": {
						"modelConfig": {
							"path": "PDS.ClvSaleStatus"
						}
					},
 
				}
			}
		}
	}
},

And it didn't help. If I hide column from the list => I get value argument of converter clv.IsObjectForSaleConverter as undefined. 

 

I looked into data saved to profile when hiding column from the list and it appears that it also modifies  viewModelConfigDiff and contains next snippet.

"viewModelConfigDiff": [
 
	{
		"operation":"remove",
		"path":[
			"attributes",
			"Items",
			"viewModelConfig",
			"attributes"
		],
		"properties":[
			"PDS_ClvSaleStatus"
		]
	}
]

 

The main point I experimented with is how to apply a converter in this line:

"visible": "$DataGrid_3c1xo0k.DataGrid_3c1xo0kDS_Stage | clv.IsObjectForSaleConverter"

When it was filled incorrectly, I saw the same problem behavior that you described. The example I provided should tell you how it needs to be filled. Please check this part in your code.

Show all comments

Hi

 

Somebody tried to enable Playbook areticles in a Freedom UI DCM's?

 

I tried, but they didn't appears

 

Some trick?

 

Thanks

Julio Falcón

Like 0

Like

2 comments
Best reply

Ryan Farley,

Thanks Ryan, I saw that it is a new component, I was looking for it in the DCM, as in Classic UI. :-)

Show all comments

Hi, when in a section that contains a multiple cases. you change from one case to another with a field change, a button is shown to validate the case change. 



Is there a way to avoid this? I want to progress bar to automatically update from one case to the other without user intervention. 

Like 1

Like

1 comments

Hi

 

Somebody know how determine, when working with a record in a Freedom UI page if it corresponds to a new record (new/copy)?

 

Thanks in advance

 

Regards

 

Julio Falcón

Like 0

Like

7 comments

Hello Julio,

const cardState = await request.$context.CardState;
if (cardState == "add" || cardState == "copy") {
     // do something here
}

Ryan

Ryan Farley,

Thanks Ryan, where did you find/get this kind of information?

Ryan Farley,

Ryan,

 

In which kind of handler request I must introduce the code? I tried in crt.OpenPageRequest, but nothing happens. The code I'm using:

 

handlers: /**SCHEMA_HANDLERS*/[ // NdosEntity_4ad7b54DS.NdosPeriodicidadMP
	{ 
		request: "crt.OpenPageRequest",
		handler: async (request, next) => {
			const okBtn = {
				key: "OK",
				config: {
					color: "accent",
					caption: "OK"
				}
			};
 
			const cancelBtn = {
				key: "CANCEL",
				config: {
					color: "primary",
					caption: "Salir"
				}
			};
 
			// Nuevo o Copia
			const cardState = await request.$context.CardState;
 
			// Mensaje...
			const result = await request.$context.executeRequest({
				type: "crt.ShowDialogRequest",
				$context: request.$context,
				dialogConfig: {
					data: {
						message: ( cardState == "add" || cardState == "copy" ) ? "New: Este es un nuevo registro" : "Existing one: Este registro ya existe" ,
						actions: [ okBtn, cancelBtn ]
					}
				}
			});
 
			if (result === "OK") {
				// Clica en OK
 
			}
 
			/* Siguiente handler, retorna resultado */
			return next?.handle( request );
 
		},	
	},
]

Julio.Falcon_Nodos,

You would add this in the page you’re opening, not in the code that opens the page. What is the intent you’re trying to produce? I assume that in a page you’re wanting to know if the page is in add mode vs edit. Correct? To accomplish this you’d add something such as a crt.HandleViewModelResumeRequest on the page and check the cardstate there. 

Thanks Ryan, I'm also try using crt.HandleViewModelResumeRequest, but nothnig happens.

 

What I need is that when I open the page "Air Equipment/NdosPage_3ud8c3e" it can detect if I am working with a new record and do something. So it is in the code of this page, where I enter the commented code, compile, open an existing record and create a new one and the code entered does not execute/does not work in any situation.

 

If I add the code inside a crt.HandleViewModelAttributeChangeRequest, it works, but it stays 

in loop and to exit I have to go back in the browser.

 

I made a short video to show what I'm doing and where the code is in case it helps to understand, see at

https://share.vidyard.com/watch/NRBjhx3hjzCi9sZ2x5qsSK?

 

In Classic UI I've the onEntityInitialized method to execute when open the page, but in Freedom is very different

 

Thanks again

Julñio

Julio.Falcon_Nodos,

Hello Julio,

Does it also not enter the handler if you try adding a "crt.HandleViewModelInitRequest"?

Ryan Farley,

No Ryan, I didn't understand what's wrong with my code :-(, 

 

Show all comments