Hi,



I have been working on adding new custom components using the new freedom UI following the below Creatio article.

https://academy.creatio.com/docs/developer/front_end_development_freedom_ui/remote_module/implement_a_remote_module/overview



After doing some additional research I was able to add some custom components successfully. But I'm kind of stuck on where I need to pass the data from Creatio's side to that specific angular component. Please refer to the below screenshots of my code snippets and if anyone has any idea on what I'm missing can you guide me or provide some resources to get more idea on this?

 

Below is the "card.component.html" file:

<mat-card class="card-class" *ngFor="let val of valuelist" >
    <mat-card-header></mat-card-header>
    <mat-card-content class="content-wrapper">
        <div fxFill fxLayout="row">
            <div fxFlex="30" fxLayout="space-around center">
                <div fxFlex fxLayoutAlign>
                    <img mat-card-sm-image src="https://material.angular.io/assets/img/examples/shiba2.jpg" alt="Free Image" class="responsive-image"  >
                </div>
                <div fxFlex fxLayoutAlign>
                    <img mat-card-sm-image src="https://material.angular.io/assets/img/examples/shiba2.jpg" alt="Free Image" class="responsive-image" >
                </div>
            </div>
            <div fxFlex="55" fxLayout="column" fxLayoutAlign="center start" class="contentN" >
                <mat-card-title>{{val}}</mat-card-title>
                <mat-card-subtitle>{{val}}</mat-card-subtitle>
            </div>
            <div fxFlex="15" fxLayout fxLayoutAlign="center center" class="contentP">
                <img mat-card-sm-image src="https://material.angular.io/assets/img/examples/shiba2.jpg" alt="Free Image" class="responsive-image" >
            </div>
        </div>
    </mat-card-content>
    <mat-card-footer></mat-card-footer>
</mat-card>

 As in the above, from using ngFor I'm adding cards based on the data which are coming from the "valuelist". Below is the example of the "card.component.ts" file:



 

import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { CrtInput, CrtOutput,CrtInterfaceDesignerItem, CrtViewElement } from '@creatio-devkit/common';
 
 
@Component({
  selector: 'mlcgd-card',
  templateUrl: './card.component.html',
  styleUrls: ['./card.component.scss'],
  //encapsulation: ViewEncapsulation.ShadowDom
})
 
/* Add the CrtViewElement decorator to the Textpromt component. */
@CrtViewElement({
  selector: 'mlcgd-card',
  type: 'mlcgd.Card'
})
 
/* Add the CrtViewElement decorator to the InputComponent component. */
@CrtInterfaceDesignerItem({
  /* Manage the element layout in the library of the Freedom UI Designer. */
  toolbarConfig: {
    caption: 'Card View',
    name: 'CardView',
    /* The path to the component image. */
    icon: require('!!raw-loader?{esModule:false}!./icon.svg'),
    defaultPropertyValues: {
      label: 'Card View'
    }
  }
})
 
export class CardComponent {
 
  valuelist:string[] = [];
 
  constructor() {}
 
  @Input()
  @CrtInput()
  /* ...............The input value. */
  public value: string = 'Lakindu, Chinthana, Deshan';
 
  @Output()
  @CrtOutput()
  /* ................Track input value changes. */
  public valueChange = new EventEmitter<string>();
 
  ngOnInit(): void {
    this.valuelist = this.value.split(',')
  }
}

As you can see in the above code snippet I have a string called "value" and I have hardcoded 3 values for that. What I need to achieve is without hardcoding the data I need to get those data from the Creatio's end like from a field. So to do that I need to modify the code which is gonna add to the viewconfig array in the client schema. Please refer to the below Code snippet. And I need help with modifying it accordingly to pass the data from Creatio to the component.

 

{
				"operation": "insert",
				"name": "Card_hs3upn6",
				"values": {
					"type": "mlcgd.Card",
					"label": "Card View",
					"value": "$MLCGDName"
				},
				"parentName": "FlexContainer_08awxs2",
				"propertyName": "items",
				"index": 0
			}

Kind Regards,

Lakindu

Like 4

Like

5 comments

Hello,

You can find an example of working with the field value in these articles.

https://academy.creatio.com/docs/developer/front_end_development_freedo…

https://academy.creatio.com/docs/developer/front_end_development_freedo…

They described information on how to create a validator/converter for the value in a field.

Hello,



Thanks for sharing this but I'm afraid this might not be the one that I'm looking for. Anyways do you have anything related to dashboards? Like adding a new dashboard element using a remote module?



I was able to add some components there but for the moment I am kind of stuck at passing the data to the created component using the remote module.

Unfortunately, no, we don't have such examples.

To be honest, the remote module is quite a fresh feature, which means that currently, it doesn't have much logic. If possible, it would be better to use other methods to add your business logic.

Lakindu Yasomith,

Maybe this article can help you:

https://academy.creatio.com/docs/developer/front_end_development_freedo…

 

If not, please let us know. Maybe you can describe your case in more detail for support@creatio.com.

Lakindu Yasomith,

Hi,

 

I'm also working on a custom component and have the same issue.

Did you find a solution to this?

 

Br,

Robert

Show all comments

Hello,

i made a module, in freedom-ui mode, to display custom content in Accounts_FormPage. The module init is triggered with crt.HandleViewModelInitRequest handler.



here is the useful module code :

/* AMD module declaration. */
// jshint esversion: 11
define("UsrAccountHistoriqueProduit", ["@creatio-devkit/common"], function(sdk) {
    //
    return {
        //**--------------------------------- Init module -------------------------------**/
        onInitialized: async function($context) {
            const idAccount = await $context.Id;
            const my = this;
            
            /* Declare the class. */
            class UsrAccountHistoriqueProduit extends HTMLElement  {
                constructor(args) {
                    super();
                    this.displaycontent();
                }
                async displaycontent() {
                    var shadowDom = this.attachShadow({mode: 'open'});
                    shadowDom.innerHTML = "";
                    
                    const html = await my.statsOrderProduct(idAccount);
                    shadowDom.innerHTML = html;        
                }
            }

            /* Register the component. */
            customElements.define('usr-historiqueproduit-view-element', UsrAccountHistoriqueProduit);

            /* Register the web component as a view element. */
            sdk.registerViewElement({
                type: 'usr.CustomViewElement',
                selector: 'usr-historiqueproduit-view-element'
            });

        },
...

It works fine at load of the page, then when viewing a second account, i have this error message : 

ERROR DOMException: Failed to execute 'define' on 'CustomElementRegistry':
the name "usr-historiqueproduit-view-element" has already been used with this registry



i think i can clean up the registered viewElement with the crt.HandleViewModelDestroyRequest handler, but i did not found cleaning method in the sdk objet.

 

How should it be done please ?

 

best regards,

Patrice

Like 0

Like

2 comments
Best reply

Hi Patrice,

 

This error message occurs since the element with "usr-historiqueproduit-view-element" selector was already registered upon first init:

sdk.registerViewElement({
                type: 'usr.CustomViewElement',
                selector: 'usr-historiqueproduit-view-element'
            });

In your onEnityInitialized you need to add additional check if the element was registered in DOM or not (for example as proposed here) and as a result of this check perform registration or not.

Hi Patrice,

 

This error message occurs since the element with "usr-historiqueproduit-view-element" selector was already registered upon first init:

sdk.registerViewElement({
                type: 'usr.CustomViewElement',
                selector: 'usr-historiqueproduit-view-element'
            });

In your onEnityInitialized you need to add additional check if the element was registered in DOM or not (for example as proposed here) and as a result of this check perform registration or not.

Thanks Oleg,

i was not aware of the CustomElementRegistry api, i thaught it was a Creatio thing.

Now i know where the documentation is ! (mozilla.org)

 

Best regards,

Patrice

Show all comments

How to make a field in the expanded list read-only by default or by a condition

Like 0

Like

4 comments

Hello,

 

You can customize a business rule to cover this need:

Set up business rules

Hi @Kalymbet .Can you guide little bit more. The link which you have shared that is not opening

These answers do not answer the question of how to make a specific field in a list read only. i.e. have an editable list, but make some columns always be read only for the user. I presume this isn't possible in Creatio currently though?

Show all comments

Hello Community!

 

I'm trying to fill a field with the result of a simple calculation (e.g. field A - field B).

 

However, when I create the business rule and select "set field" as action, I can only provide a constant value and not a formula...am I missing something?

 

Here is a screenshot of the 

 

I know that I can use a business process to achieve this, but this would be much more simpler and elegant I think.

 

BR,

Robert

Like 0

Like

4 comments
Best reply

It's not yet available in Freedom UI --> Creatio Roadmap indicates for Q4 2023 https://academy.creatio.com/docs/release/creatio-roadmap?check_logged_i…

I forgot to add that I use version 8.0.10.4735

It's not yet available in Freedom UI --> Creatio Roadmap indicates for Q4 2023 https://academy.creatio.com/docs/release/creatio-roadmap?check_logged_i…

Damien Collot,

Thanks Damien, at least I know that I did overlook something.

Hi Damien,

I do not have access to the link to the roadmap.

I get this message:

"

Access denied

You are not authorized to access this page.

"

Is it restricted?

It is very interesting information.

Thanks,

Luis

Show all comments

How to add new icon in the icon list for Freedom Ui

Like 1

Like

4 comments

Not possible to add.

It would be great to be able to use any mat-icon. For now, I would love to at least get a complete list of the icons available. I’ve noticed that the list changes depending on the context of what the icon is for, although you can change the icon name in the viewConfigDiff to any available and it works (as long as you know the available icon names)

Ryan

Hello,



Unfortunately, there is currently no way to add a new icon in the icon list for Freedom UI.



However, a task has already been registered in our R&D team to consider and implement such a feature in future releases. In case you would like to check what stage this task is at, I am sending you the task number: PR-28339. Feel free to share this number with us at any time and ask your questions.

Hello @Malika, Can you please give me information of this task number PR-28339 

Hello @Malika any update on this task PR-28339 

Show all comments

Hi everyone,

 

How can we override the onClick functionality of the attachment link? Or is there any way to disable the link?



Thanks & regards,

Ramya

Like 0

Like

3 comments

Hello Ramya,

 

We thought on overriding the logic of the crt.DownloadEntityFileRequest request, but the handler doesn't trigger upon clicking the file. I will ask our R&D team to make it possible to control the download of files out-of-the-box and do it in the nearest releases.

 

Thank you!

Oleg Drobina,

 

Thank you for the swift response. Since overriding is not possible as of now, is there any way to disable the link? Something similar to the Classic UI diff value "showValueAsLink" : false?



Regards,

Ramya

Oleg Drobina,

 

Can you also elaborate what handler is getting called if it is not "crt.DownloadEntityFileRequest" ?

Show all comments

Hello community,

I have a requirement to add a button in ShellHeaderToolbar in the MainShell. I tried adding a button but was not successful as ShellHeaderToolbar is not of container type. Is there any workaround for this?

Regards,

Pavan Manne

Like 1

Like

1 comments
Best reply

I did this in my Recently Viewed Records add-on in the marketplace, it wasn't easy and took a bit of a hack. You'll need to override the MainShell  and what I ended up doing is add a button into the shell that I move at runtime into the ShellHeaderToolbar. Feel free to look at the source of that add-on to see what I am doing to accomplish this. Ideally, it would be great if that were a container and you could add items to it, but sadly not the case.

Ryan

I did this in my Recently Viewed Records add-on in the marketplace, it wasn't easy and took a bit of a hack. You'll need to override the MainShell  and what I ended up doing is add a button into the shell that I move at runtime into the ShellHeaderToolbar. Feel free to look at the source of that add-on to see what I am doing to accomplish this. Ideally, it would be great if that were a container and you could add items to it, but sadly not the case.

Ryan

Show all comments

Hi everyone,

 

Is there a way to obtain the ID of the selected file in attachments in a Freedom UI section? Looking for an equivalent of activeRow / this.get("SelectedRows") for Freedom UI.

 

Regards,

Ramya

Like 1

Like

3 comments
Best reply

Yes. This is something I would need as well. I've not tried this, but maybe it's possible to add to the rowToolbarItems for the attachments list and get the selected Id from the handler there?

Ryan

Yes. This is something I would need as well. I've not tried this, but maybe it's possible to add to the rowToolbarItems for the attachments list and get the selected Id from the handler there?

Ryan

Ryan Farley,

 

Thanks a lot for the response. This worked!

You can pass the attachment Id in the params as mentioned below:

"rowToolbarItems": [{
	"type": 'crt.MenuItem',
	"caption": 'Get attachment id',
	"icon": 'open-button-icon',
	"clicked": {
		"request": 'psg.MyCustomHandler',
		"params": {
			"Id": "$AttachmentList.AttachmentListDS_Id"
		}
	}
}]

Regards,

Ramya

Ramya R,

Glad to hear this list can also be extended, great news. 

Ryan

Show all comments

Hello, 

I'm using [Autonumber] field for managing record number data automatically like in the documentation   , Set up an [Autonumber] field | Creatio Academy 

Now, i need to reset the increment  to the 0  if the user clicks  on a button

How to reset the increment ? any idea !

Thank you 

Like 1

Like

1 comments

Hi,

There's no direct way to reset the auto number field. 

It's based on the Sequence object in the DB, you can run the script that will restart the sequence. For example, you could create a business process that will execute a script that will restart the sequence. 



Best regards,

Yuri

Show all comments

How can i hide / show a field based on the user role in freedom UI with business rules or with js code?

Thank you

Like 2

Like

7 comments
Best reply

You can do this with code on a Freedom UI page. 

1) Make sure you add "@creatio-devkit/common" to the page as sdk

2) First add an attribute to the viewModelConfig. I'll call the attribute "IsUserInRole since we'll set it to true/false if the user is in the role. 

viewModelConfig: /**SCHEMA_VIEW_MODEL_CONFIG*/{
    "attributes": {
        "IsUserInRole": {}
    }
}/**SCHEMA_VIEW_MODEL_CONFIG*/

3) Bind the attribute to the visible property of the control by adding the following to the control in the viewModelDiff

"visible": "$IsUserInRole"

4) Now when the view model is initialized, basically the Freedom UI equivalent of the onEntityInitialized on classic pages, do a query using the model to determine if the current user is in the role. We'll use that result to set the attribute:

{
    request: "crt.HandleViewModelInitRequest",
    handler: async (request, next) =&gt; {
        await next?.handle(request);
        // get current user
        const sysValuesService = new sdk.SysValuesService();        
        const sysValues = await sysValuesService.loadSysValues();
        const currentUserContact = sysValues.userContact;
 
        // create model query
        userRoleModel = await sdk.Model.create("SysUserInRole");
        const filter = new sdk.FilterGroup();
        await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "SysRole.Name", "The Role Name Here");
        await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "SysUser.Contact", currentUserContact.value);
 
        // workaround for filters, will be fixed in 8.1
        const newFilter = Object.assign({}, filter);
        newFilter.items = filter.items;
 
        const results = await userRoleModel.load({
            attributes: ["Id"],
            parameters: [{
                type: sdk.ModelParameterType.Filter,
                value: newFilter
            }]
        });
 
        // now set attribute
        request.$context.IsUserInRole = results.length &gt; 0;
    }
}

I didn't test that code, but it should be pretty close. If anything you might need to play with the filter for the model query.

Ryan

Hello,

 

Unfortunately, there is no way to add visibility to the field based on user role via Section Wizard.

 

But we've registered it in our R&D team backlog for consideration and implementation in future application releases.

 

Thank you for helping us to improve our product. 

Bogdan,

but is it possible to calculate page parameter based on Operation permission? And then use this parameter in business rule?

You can do this with code on a Freedom UI page. 

1) Make sure you add "@creatio-devkit/common" to the page as sdk

2) First add an attribute to the viewModelConfig. I'll call the attribute "IsUserInRole since we'll set it to true/false if the user is in the role. 

viewModelConfig: /**SCHEMA_VIEW_MODEL_CONFIG*/{
    "attributes": {
        "IsUserInRole": {}
    }
}/**SCHEMA_VIEW_MODEL_CONFIG*/

3) Bind the attribute to the visible property of the control by adding the following to the control in the viewModelDiff

"visible": "$IsUserInRole"

4) Now when the view model is initialized, basically the Freedom UI equivalent of the onEntityInitialized on classic pages, do a query using the model to determine if the current user is in the role. We'll use that result to set the attribute:

{
    request: "crt.HandleViewModelInitRequest",
    handler: async (request, next) =&gt; {
        await next?.handle(request);
        // get current user
        const sysValuesService = new sdk.SysValuesService();        
        const sysValues = await sysValuesService.loadSysValues();
        const currentUserContact = sysValues.userContact;
 
        // create model query
        userRoleModel = await sdk.Model.create("SysUserInRole");
        const filter = new sdk.FilterGroup();
        await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "SysRole.Name", "The Role Name Here");
        await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "SysUser.Contact", currentUserContact.value);
 
        // workaround for filters, will be fixed in 8.1
        const newFilter = Object.assign({}, filter);
        newFilter.items = filter.items;
 
        const results = await userRoleModel.load({
            attributes: ["Id"],
            parameters: [{
                type: sdk.ModelParameterType.Filter,
                value: newFilter
            }]
        });
 
        // now set attribute
        request.$context.IsUserInRole = results.length &gt; 0;
    }
}

I didn't test that code, but it should be pretty close. If anything you might need to play with the filter for the model query.

Ryan

Thank you. That helps a lot.

Ryan Farley,



I have tried a similar case, where on saving a record writing a validation to check whether it has unique "Code".

 

request: "crt.SaveRecordRequest",handler: async (request, next) =&gt; {
// Add any code to execute *before* the save here
 
var accountModel = await sdk.Model.create("Account");
 
const filter = new sdk.FilterGroup();
var codeValue = await request.$context.StringAttribute_enupz4g;
await filter.addSchemaColumnFilterWithParameter(sdk.ComparisonType.Equal, "SMCode", codeValue);
 
	const newFilter = Object.assign({}, filter);
	newFilter.items = filter.items;
 
	const accounts = await accountModel.load({
		attributes: ["Id"],
		parameters: [{
		type: sdk.ModelParameterType.PrimaryColumnValue,
		value: newFilter
		}]
	});
	if(accounts.length &gt; 0){
		isSave = false;
		//Show warning Message
		request.$context.executeRequest({
		type: "crt.ShowDialogRequest",
		$context: request.$context,
		dialogConfig: {
		data: {
		message: "Code already already exists",
		actions: [{
			key: "OK",
			config: {
			color: "primary",
			caption: "OK"
			}
		}]
		}
		}
	});
	}
else{
return next.handle(request);
}
}



I followed your code to check any account has the similar code. Seems like, there is an issue in the filter it throws the below error.







Can you help me in adding the proper filter in this Freedom UI? Or provide a sample code to add filters to retrive data from an entity.



Regards,

Adharsh S

Adharsh,

Change this part: 

const accounts = await accountModel.load({
	attributes: ["Id"],
	parameters: [{
		type: sdk.ModelParameterType.PrimaryColumnValue,
		value: newFilter
	}]
});

To this: 

const accounts = await accountModel.load({
	attributes: ["Id"],
	parameters: [{
		type: sdk.ModelParameterType.Filter,
		value: newFilter
	}]
});

Note, the difference in type. You're specifying a filter, not providing a primary column value. 

Ryan

This is a very common requirement for all clients, this really should be added to the no code Page Designer. Similarly with Operation permissions to be used in visibility conditions.

Show all comments