Directives And Filters

Provided classes, directives, filters, services

For component or serivce development Servoy has a public api that can be installed with "npm i @servoy/public" for a service or component package. And then needs to be imported in the angular @NgModule declartion:

import { ServoyPublicModule } from '@servoy/public';

imports: [
      ServoyPublicModule,
      ]

This will provide various Angular Directives, Filters and Services that a component or service can use to integrate into the servoy product or use it as generic helpers.

For component development the most important one is the ServoyBaseComponent because every component needs to extend that one to get the default interface/behavior for integrating into the NGClient.

Provided Services/Classes

ServoyPlublicService

This service has various function to interact with the Servoy Environment.

it can be imported by:

import { ServoyPublicService } from '@servoy/public';

constructor(private servoyService: ServoyPublicService) {}

See the api below:

class ServoyPublicService {
    /**
     * get the character for the NumberSymbol that is given like Decimal from the current locale of the client.
     */
    public getLocaleNumberSymbol(symbol: NumberSymbol): string {
        return getLocaleNumberSymbol(this.getLocale(), symbol);
    }
    /**
     * Let the system op the file dialog, this is used by the {@link UploadDirective}
     */
    public showFileOpenDialog(title: string, multiselect: boolean, acceptFilter: string, url: string): void;

    public showMessageDialog(dialogTitle: string, dialogMessage: string, styleClass: string, values: string[], buttonsText: string[], inputType: string): Promise<string>;
    /**
     * This created the correct {@link JSEvent} object that is used for handler calls to the server, tries to fill in as much as it can.
     */
    public createJSEvent(event: EventLike, eventType: string, contextFilter?: string, contextFilterElement?: unknown): JSEvent;
    /**
     * Returns the current locale string the client is in.
     */
    public getLocale(): string;
    /**
     * Returns the full {@link Locale} object of the client.
     */
    public getLocaleObject(): Locale;
    /**
     * Internal api, directives can use this to call server side registered services. (this is internal Servoy services).
     * Do not try to use this instead of callServiceServerSideApi() - which has to be used for calling server side JS scripting of custom services from packages.
     */
    public callService<T>(serviceName: string, methodName: string, argsObject: unknown, async?: boolean): Promise<T>;

    /**
     * Get and listen for i18n message keys, this will call I18NListener.messages() for with an object of key value pairs for all the keys given for the current locale.
     * It will also call that same method again if the locale changed in the client with the updated values.
     * If the caller is destroyed the I18NListener.destroy() must be called to deregister this listener.
     */
    public listenForI18NMessages(...keys: string[]): I18NListener;
    /**
     * Use this to call a script at the server that was given to use by a function spec property.
     */
    public executeInlineScript<T>(formname: string, script: string, params: unknown[]): Promise<T>;
    /**
     * Services can use this to call there own server side api
     */
    public callServiceServerSideApi<T>(servicename: string, methodName: string, args: Array<unknown>): Promise<T>;
    /**
     * Returns an upload url that can be used to push binary data to the given form/component/property combination. (MediaUpload component)
     */
    public generateUploadUrl(formname: string, componentName: string, propertyName: string, tus?: boolean): string;
    /**
     * Returns an upload url to push binary data to a service serverside function (that gets the file as an argument)
     */
    public generateServiceUploadUrl(serviceName: string, apiFunctionName: string, tus?: boolean): string;
    /**
     * Use this to get a url to a solutions media for download or src/href
     */
    public generateMediaDownloadUrl(media: string): string;
    /**
     * returns the ui property value for the given key that is set as a ui property on the application.
     */
    public getUIProperty(key: string): any;
    /** 
      * returns the {@link IFormCache} on the client to be able to get some extra data from it like size of that form.
      */
    public getFormCacheByName(containedForm: string): IFormCache;

    /**
     * Services should use this function to push there changed model data to the server (when needed),
     * so the data is accesable in a servoy solution or stored for a browser refresh.
     *
     * @param propertyValue the new value that the service has (and should send to server) for the given propertyName; if you didn't assign it yet to the service's property,
     *                      this method will do it for you.
     * @param oldPropertValue the value that this property used to have before (or has if you did not change the reference - in this case it should be the same as �propertyValue�);
     *                        this value is used in case of smart types (custom array/custom objects) in order to detect if it's a full change by reference for example
     */
    public sendServiceChangeToServer(serviceName: string, propertyName: string, propertyValue: unknown, oldPropertyValue: unknown): void;
    /**
     * show a form popup {@link PopupForm}
     */
    public showForm(popup: PopupForm): void;
    /**
     * cancel/hide the form popup that is currently showing.
     */
    public cancelFormPopup(disableClearPopupFormCallToServer: boolean): void;

    /**
     * Returns the value of the testing mode flag (servoy.ngclient.testingMode) from the admin page
     */
    public isInTestingMode(): boolean;
}

ServoyBaseComponent

Every component needs to extends this component

 import { ServoyBaseComponent } from '@servoy/public';
 
 export class MyComponent extends ServoyBaseComponent<HTMLDivElement> {}

By default this BaseComponent has 3 inputs:

 @Input() name: string;
 @Input() servoyApi: ServoyApi;
 @Input() servoyAttributes: { [property: string]: string };

that are injected and exposed.

It also has function that exposes the getNativeElement() (the html tag where #element attribute is in). Also getNativeChild() can by overwritten if you have a nested attribute that is more the real element. By default getNativeChild() returns the same thing as getNativeElement()

ServoyApi

The ServoyApi class is the api that interacts with the servoy system (calling the server).

See the api below:

class ServoyApi {
    /**
     * This should be called by components when they want to show a form, optionally a relationname or formindex can be given.
     * It will return a Promise that gives a boolean if the form could be shown (then the component can actually show this form)
     */
    formWillShow(formname: string, relationname?: string, formIndex?: number): Promise<boolean>;
    /**
     * This should be called by components when they it wants to hide a form, optionally a relationname or formindex can be given and
     * also the form/relation/index that should be shown when the given form can be hidden so there is only 1 call to hide one form and show another.
     *
     * It will return a Promise that gives a boolean if the form could be hidden (onHide of a form doesn't block the hide)
     */
    hideForm(formname: string, relationname?: string, formIndex?: number, formNameThatWillShow?: string, relationnameThatWillBeShown?: string, formIndexThatWillBeShown?: number): Promise<boolean>;
    /**
      * Call to notify the server when this property is gone in edit mode (focus in a field). This can also be configured by using the {@link StartEditDirective}
      */
    startEdit(propertyName: string): any;
    /**
      * This apply is only needed for nested dataproviders, so a dataprovider property of custom type, this will push and apply the data to the data model.
      * Normal main spec model dataprovider should be pushed using an Change Emitter.
      */
    apply(propertyName: string, value: unknown): any;
    /**
      * Call this components serverside api with the given arguments
      */
    callServerSideApi(methodName: string, args: Array<unknown>): any;
    /**
      * Returns true if the component is currently rendered in the designer (so it can render with some sample data if needed)
      */
    isInDesigner(): boolean;
    /**
      * Returns true if this component can trust the html it wants to display (no need to sanatize it).
      * This can be a client property set on this component itself or more application wide.
      */
    trustAsHtml(): boolean;
    /**
      * Returns true if this component is placed on a css positioned form (not responsive)
      */
    isInAbsoluteLayout(): boolean;
    /**
      * Returns the markupid that this component can use for itself, can be used like this in the template:  [id]="servoyApi.getMarkupId()"
      */
    getMarkupId(): string;
    /**
      * Returns the formname where this component is part of.
      */
    getFormName(): string;
    /**
      * Internal api, used by {@link ServoyBaseComponent} to register itself to implementors of this ServoyApi object (like form containers)
      */
    registerComponent(component: ServoyBaseComponent<HTMLElement>): any;
    /**
     * Internal api, used by {@link ServoyBaseComponent} to unregister itself to implementors of this ServoyApi object (like form containers)
      */
    unRegisterComponent(component: ServoyBaseComponent<HTMLElement>): any;
    /**
      * Returns the value for the given client property key that was set at the server side on this component.
      */
    getClientProperty(key: string): any;
}

FormattingService

This is a service that can perform various data -> string formatting or string -> data unformatting on various types, based on the format object that Servoy provides through the format property

import { FormattingService } from '@servoy/public';

constructor(private formattingService: FormattingService) {
    this.formattingService.format(data,format)
}

The api:

/**
 * format the data give with the {@link Format} object give, optionally using the display or edit format.
 */
public format(data: any, format: Format, useEditFormat: boolean): string 

/**
 * utility function to test if a certain key is pressed
 */
public testKeyPressed(event: KeyboardEvent, keyCode: number) 

/**
 * utility function to test if only numbers ar pressed.
 */
public testForNumbersOnly(e, keyChar, vElement, vFindMode, vCheckNumbers, vSvyFormat, skipMaxLength)
/**
 * calls the { @link #unformat} function for unformatting/parsing the data given
 */
public parse(data: any, format: Format, useEditFormat: boolean, currentValue?: any, useHeuristics?: boolean): any

/**
 * unformats/parse the give data according to the given format and type 
 */
public unformat(data: any, servoyFormat: string, type: string, currentValue?: any, useHeuristics?: boolean): any

MaskFormat

This is a helper class in the formatting area. The formatting service will also use this internally when the format is a configured to be a mask.

import { MaskFormat } from '@servoy/public';

this.maskFormat = new MaskFormat(this.format, this._renderer, this.elementRef.nativeElement, this.formattingService, this.doc);
// do call destroy when not used anymore
this.maskFormat.destroy();

LoggerFactory

This service can be used by components and services to create a Logger for a specific class ang log to certain levels.

import { LoggerFactory, LoggerService } from '@servoy/public';

private log: LoggerService;

constructor(private loggerFactory: LoggerFactory) {
    this.log = logFactory.getLogger('MyComponent');
}

LoggerService

This is returned by the getLogger() call on the factory. It has the various log functions on the different log levels. Besides that it has a helper method to build a message if that message is a lot of string concatting and should only be build if the message is really logged

this.log = logFactory.getLogger('MyComponent');
this.log.error('this is an error');
this.log.info(this.log.buildMessage(() => 'a' + someVariable + ' large message'));

The api:

logLevel:LogLevel;

spam(...data: unknown[])


debug(...data: unknown[])

info(...data: unknown[])

warn(...data: unknown[])

error(...data: unknown[])

public buildMessage(message: string | ( () => string )) 

public toggleDebugMode()

The LogLevel is enum:

enum LogLevel {
    ERROR = 1,
    WARN,
    INFO,
    DEBUG,
    SPAM
}

TooltipService

The tooltip service is a service that can also be used standalone if you can't use the directive) The directive uses this service under the hood.

import { TooltipService } from '@servoy/public';

constructor(private tooltipService: TooltipService) {}

The api:

/**
 * Showsthe tooltip on the screen on the position of the mouse event, showing the message with a initial delay and dismissing it after dismissDelay.
 */
public showTooltip(event: MouseEvent, message: string, initialDelay: number, dismissDelay: number)

/**
 *  hides the tooltip directly that is currently showing.
 */
public hideTooltip()

Provided Directives

svyFormat

This directive takes care of the formatting to the data that is given, it is a ControlValueAccessor in combination of the NgModel It expects that it gets a Format object assigned that a component gets to the format

In the component typescript code:

import { Format, FormatDirective } from '@servoy/public';
@Input() format: Format;

// you can also get a reference to the directive instance by calling writeValue directly on it.
@ViewChild(FormatDirective) svyFormat: FormatDirective;

the tempplate:

[svyFormat]="format"
[findmode]="findmode"

It has also a attribute/property by itself "findmode" so the formatter knows when it is findmode and shouldn't try to format at all.

svyStartEdit

This directive calls startEdit on focus through the clientside servoyApi object which a component gets by default and is exposed by the ServoyBaseComponent which all components should extend. The value that it needs is the property where the edit is for, as an example: [svyStartEdit]="'dataProviderID'", so this is the string of the property where it should work on, not the value (see the '' inside the "") and it needs a reference to the actual component through the hostComponent property: [hostComponent]="this"

the template:

[svyStartEdit]="'dataProviderID'"
[hostComponent]="this"

svyDecimalKeyConverter

This directives monitors the key presses to see if the decimal key is press and inserts the correct , or . for the locale the user is in. In expect to get assigned the format so it can check it is a number format.

the template:

[svyDecimalKeyConverter]="format"

svyTooltip

A directive that takes care of the (html) tooltips that must be set on the component, it is a wrapper around the tooltipservice so you don't have to do the event bindings your self.

the template:

[svyTooltip]="toolTipText"

svyTabFix

This directive should be used by components that are showing popups like the typeahead when the component needs to close the popup when the tab key is pressed The component needs to implement IPopupSupportComponent

the template:

[svyTabFix]="this"

the component ts:

import { IPopupSupportComponent, ServoyBaseComponent } from '@servoy/public';

export class Typeahead extends ServoyBaseComponent<HTMLInputElement> implements IPopupSupportComponent{
 closePopup(){
  this.dismissPopup();
 }
}

svyUpload

This directive is a wrapper around ServoyPlublicService.showFileOpenDialog() and ServoyPlublicService.generateUploadUrl() To let the user on click on this component opens a file open dialog and then upload the selected file to the server for the given form and component. Currently the property is hardcoded as 'dataProviderID'. so it will upload to "[formname].[componentname].dataProviderID"

the template:

svyUpload 
[formname]='servoyApi.getFormName()'
[componentName]='name'

sabloTabseq

This directive should get as a value the tabSequence property of the component

See Sablotabsequence for more information what a component can do with it (like being a container itself for multiply tabsequences)

Provided Filters

Besides these directives there are also some angular filters:

formatFilter

This is a wrapper around the FormattingService that you can use in labels, so none editable components, instead of using the FormatDirective in components that support edit of data.

[innerHTML]="dataProviderID | formatFilter:format | htmlFilter | trustAsHtml:isTrustedHTML() | designFilter:servoyApi.isInDesigner()"

The given value of the dataproviderID property will go through the format filter that gets as the argument the format property to format the data.

htmlFilter:

only returns html that is inside tags so filters the rest outside of it.

[innerHTML]="dataProviderID | formatFilter:format | htmlFilter | trustAsHtml:isTrustedHTML() | designFilter:servoyApi.isInDesigner()"

After the format the htmlFilter will then strip the body and the parents tags if the html string had those.

trustAsHtml

trustAsHtml:servoyApi.trustAsHtml() if the give boolean is true, then the input will not be sanitized but use as is.

[innerHTML]="dataProviderID | formatFilter:format | htmlFilter | trustAsHtml:isTrustedHTML()"

After the formatting of the value the trustAsHtml will mark the give value as trusted (if the argument of isTrustedHTML() is true) so then it will not be sanitized or the sanitizer of Angular will sanitize it.

The servoyApi can be asked if it should be trusted (set by the system or a ui property on the component). But it can also be that the component has a property that supports this:

isTrustedHTML(): boolean {
  if (this.servoyApi.trustAsHtml() || this.showAs === 'trusted_html') {
    return true;
  }
  return false;
}

emptyValue

This filter inserts a '\u00A0' for a '' so it is a none breaking space in the html.

[innerHTML]="dataProviderID | formatFilter:format | htmlFilter | trustAsHtml:isTrustedHTML() | emptyValue"

"

notNullOrEmpty

This filter filters all null or empty values from an array so that you only loop over actual values in a *for loop in a template:

<label *ngFor="let item of valuelistID | notNullOrEmpty; let i = index;">

Last updated