File

src/lib/directives/clientClickDirective/clientClick.directive.ts

Description

Angular directive to handle the OnClientClick script and the Click event when a button is clicked.

Implements

OnInit

Metadata

Index

Properties
Methods
Inputs
HostListeners
Accessors

Constructor

constructor(internalEventHandler: InternalEventHandlerService, linkbuttonComponent: LinkButtonComponent, buttonComponent: ButtonComponent)

Creates an instance of ClientClickDirective.

Parameters :
Name Type Optional
internalEventHandler InternalEventHandlerService No
linkbuttonComponent LinkButtonComponent No
buttonComponent ButtonComponent No

Inputs

commandArgument
Type : string

Gets/sets the commandArgument property.

commandName
Type : string

Gets/sets the commandName property.

eventsContext
Type : any

Property used to save the context where the functions need to be executed. Usually it is used as [eventsContext]='this' in the migrated control.

model
Type : any

Property used to save the model.

onClientClick
Type : string

Gets/sets the onClientClick property.

HostListeners

click
Arguments : '$event'

Listener for the click event.

Parameters :
Name Optional
event No

Methods

clickListener
clickListener(event: any)
Decorators :
@HostListener('click', ['$event'])

Listener for the click event.

Parameters :
Name Type Optional
event any No
Returns : void
executeAsJSCode
executeAsJSCode(jsCode: string)

Runs JS code that is not calling an external function. Example: console.log(''); return true;

Parameters :
Name Type Optional
jsCode string No
Returns : boolean

{boolean}

getClientClickFunction
getClientClickFunction(event: any)

Returns the arrow function to be called and execute the function in the right context.

Parameters :
Name Type Optional
event any No
Returns : any

{*}

getFunctionParams
getFunctionParams(func: string)

Returns a params collection based on the function name.

Parameters :
Name Type Optional
func string No
Returns : string[]

{string[]}

getOnClientClickFunctionCompleteName
getOnClientClickFunctionCompleteName()

Returns the complete function name from JS code. Example: 'return function()' => 'function()'.

Returns : string

{string}

getOnClientClickFunctionName
getOnClientClickFunctionName(functionCompleteName: string)

Returns the function name without parentheses.

Parameters :
Name Type Optional
functionCompleteName string No
Returns : string

{string}

ngOnInit
ngOnInit()

OnInit lifecycle hook.

Returns : void
onClientClickHandler
onClientClickHandler(event: any)

Handles the OnClientClick. Validates the scenarios to execute the script correctly and triggers the click if necessary.

Parameters :
Name Type Optional
event any No
Returns : boolean

{boolean}

onClientClickHasReturn
onClientClickHasReturn()

Validates if the onClientClick function has a 'return'.

Returns : boolean

{boolean}

setButtonServerClick
setButtonServerClick(clickEnabled: boolean)

Enables/disables the serverEvent for the button's click.

Parameters :
Name Type Optional
clickEnabled boolean No
Returns : void
setControlOutputEvents
setControlOutputEvents(clickOutputEnabled: boolean)

Enables/disables the emitter for the button's click.

Parameters :
Name Type Optional
clickOutputEnabled boolean No
Returns : void
setThisContext
setThisContext(params: string[], context: any)

Changes 'this' to the correct context if it is defined in the function params.

Parameters :
Name Type Optional
params string[] No
context any No
Returns : any[]

{any[]}

triggerClick
triggerClick(event: any)

Triggers the Click depending on the host component (Button/LinkButton).

Parameters :
Name Type Optional
event any No
Returns : void
triggerClickedInternal
triggerClickedInternal()

Triggers the internal Click event mechanism. This mechanism allows the Button to trigger the DataList's OnItemCommand and the Grid's OnRowCommand events.

Returns : void
triggerClickMechanism
triggerClickMechanism(event: any)

Triggers the click mechanism.

Parameters :
Name Type Optional
event any No
Returns : void

Properties

commandArgumentInternal
Type : string
Default value : ''

Property used to save the commandArgument value.

Private commandNameInternal
Type : string
Default value : ''

Property used to save the commandName value.

Private onClientClickInternal
Type : string
Default value : ''

Property to save the onClientClick value.

Accessors

commandName
getcommandName()
setcommandName(value: string)

Gets/sets the commandName property.

Parameters :
Name Type Optional
value string No
Returns : void
commandArgument
getcommandArgument()
setcommandArgument(value: string)

Gets/sets the commandArgument property.

Parameters :
Name Type Optional
value string No
Returns : void
onClientClick
getonClientClick()
setonClientClick(value: string)

Gets/sets the onClientClick property.

Parameters :
Name Type Optional
value string No
Returns : void
import {
  Directive,
  HostListener,
  Input,
  OnInit,
  Optional
} from '@angular/core';
import { ButtonComponent } from '@mobilize/winforms-components';
import { InternalEventHandlerService } from '../../services';
import { LinkButtonComponent } from '../../components/link-button/link-button.component';

/**
 * Angular directive to handle the OnClientClick script and the Click event when a button is clicked.
 *
 * @export
 * @class ClientClickDirective
 * @implements {OnInit}
 */
@Directive({
  selector: '[wmClientClick]'
})
export class ClientClickDirective implements OnInit {
  /**
   * Property used to save the model.
   *
   * @type {*}
   * @memberof ClientClickDirective
   */
  @Input()
  model: any;

  /**
   * Property to save the onClientClick value.
   *
   * @private
   * @memberof ClientClickDirective
   */
  private onClientClickInternal = '';

  /**
   * Property used to save the context where the functions need to be executed.
   * Usually it is used as [eventsContext]='this' in the migrated control.
   *
   * @type {*}
   * @memberof ClientClickDirective
   */
  @Input()
  eventsContext!: any;

  /**
   * Property used to save the commandName value.
   *
   * @private
   * @memberof ClientClickDirective
   */
  private commandNameInternal = '';

  /**
   * Gets/sets the commandName property.
   *
   * @memberof ClientClickDirective
   */
  @Input()
  set commandName(value: string) {
    this.commandNameInternal = value;
  }

  get commandName(): string {
    return this.model.CommandName ?? this.commandNameInternal;
  }

  /**
   * Property used to save the commandArgument value.
   *
   * @memberof ClientClickDirective
   */
  commandArgumentInternal = '';

  /**
   * Gets/sets the commandArgument property.
   *
   * @memberof ClientClickDirective
   */
  @Input()
  set commandArgument(value: string) {
    this.commandArgumentInternal = value;
  }

  get commandArgument(): string {
    return this.model.CommandArgument ?? this.commandArgumentInternal;
  }

  /**
   * Gets/sets the onClientClick property.
   *
   * @memberof ClientClickDirective
   */
  @Input()
  set onClientClick(value: string) {
    this.onClientClickInternal = value;
  }

  get onClientClick(): string {
    return this.model.OnClientClick ?? this.onClientClickInternal;
  }

  /**
   * Creates an instance of ClientClickDirective.
   *
   * @param {InternalEventHandlerService} internalEventHandler
   * @param {LinkButtonComponent} linkbuttonComponent
   * @param {ButtonComponent} buttonComponent
   * @memberof ClientClickDirective
   */
  constructor(
    private internalEventHandler: InternalEventHandlerService,
    @Optional() private linkbuttonComponent: LinkButtonComponent,
    @Optional() private buttonComponent: ButtonComponent
  ) {}

  /**
   * OnInit lifecycle hook.
   *
   * @memberof ClientClickDirective
   */
  ngOnInit(): void {
    this.setButtonServerClick(false);
    this.setControlOutputEvents(false);
  }

  /**
   * Enables/disables the serverEvent for the button's click.
   *
   * @param {boolean} clickEnabled
   * @memberof ClientClickDirective
   */
  setButtonServerClick(clickEnabled: boolean): void {
    /* c8 ignore else */
    if (this.model?.events?.Click != null) {
      this.model.events.Click = clickEnabled;
    }
  }

  /**
   * Enables/disables the emitter for the button's click.
   *
   * @param {boolean} clickOutputEnabled
   * @memberof ClientClickDirective
   */
  setControlOutputEvents(clickOutputEnabled: boolean): void {
    /* c8 ignore else*/
    if (this.linkbuttonComponent) {
      this.linkbuttonComponent.isClickStopped = !clickOutputEnabled;
    } else if (this.buttonComponent) {
      this.buttonComponent.isClickStopped = !clickOutputEnabled;
    }
  }

  /**
   * Listener for the click event.
   *
   * @param {*} event
   * @memberof ClientClickDirective
   */
  @HostListener('click', ['$event'])
  clickListener(event: any): void {
    this.onClientClickHandler(event);
  }

  /**
   * Handles the OnClientClick.
   * Validates the scenarios to execute the script correctly and triggers the click if necessary.
   *
   * @param {*} event
   * @return {*}  {boolean}
   * @memberof ClientClickDirective
   */
  onClientClickHandler(event: any): boolean {
    const functionCompleteName = this.getOnClientClickFunctionCompleteName();
    const functionName =
      this.getOnClientClickFunctionName(functionCompleteName);
    let response: any;
    if (functionCompleteName) {
      if (this.eventsContext && this.eventsContext[functionName]) {
        const eventFunction = this.getClientClickFunction(event);
        response = eventFunction.call(this);
      } else {
        response = this.executeAsJSCode(this.onClientClick);
      }
    } else {
      this.executeAsJSCode(this.onClientClick);
    }
    /* c8 ignore else */
    if (
      (this.onClientClickHasReturn() && response) ||
      !this.onClientClickHasReturn()
    ) {
      this.triggerClickMechanism(event);
    }
    return true;
  }

  /**
   * Returns the arrow function to be called and execute the function in the right context.
   *
   * @param {*} event
   * @return {*}  {*}
   * @memberof ClientClickDirective
   */
  getClientClickFunction(event: any): any {
    const functionCompleteName = this.getOnClientClickFunctionCompleteName();
    const functionName =
      this.getOnClientClickFunctionName(functionCompleteName);
    /* c8 ignore start */
    return () => {
      let params = this.getFunctionParams(functionCompleteName);
      params = this.setThisContext(params, event.target);
      return this.eventsContext[functionName].call(
        this.eventsContext,
        ...params
      );
    }; /* c8 ignore stop */
  }

  /**
   * Triggers the click mechanism.
   *
   * @param {*} event
   * @memberof ClientClickDirective
   */
  triggerClickMechanism(event: any): void {
    this.setButtonServerClick(true);
    this.setControlOutputEvents(true);
    this.triggerClick(event);
    this.setButtonServerClick(false);
    this.setControlOutputEvents(false);
    this.triggerClickedInternal();
  }

  /**
   * Runs JS code that is not calling an external function.
   * Example: `console.log(''); return true;`
   *
   * @param {string} jsCode
   * @return {*}  {boolean}
   * @memberof ClientClickDirective
   */
  executeAsJSCode(jsCode: string): boolean {
    /* c8 ignore else */
    if (this.eventsContext) {
      return new Function(jsCode).call(this.eventsContext);
    }
    return true;
  }

  /**
   * Returns the complete function name from JS code.
   * Example:
   * `'return function()'` => `'function()'`.
   *
   * @return {*}  {string}
   * @memberof ClientClickDirective
   */
  getOnClientClickFunctionCompleteName(): string {
    let funcName = '';
    /* c8 ignore else */
    if (this.onClientClick) {
      if (this.onClientClickHasReturn()) {
        const init = this.onClientClick.toLowerCase().indexOf('return ') + 6;
        const end = this.onClientClick.indexOf(')') + 2;
        funcName = this.onClientClick.substring(init, end).trim();
      } else if (
        /* c8 ignore else */
        !this.onClientClickHasReturn() &&
        this.onClientClick.includes('(') &&
        this.onClientClick.includes(')')
      ) {
        return this.onClientClick;
      }
    }
    return funcName;
  }

  /**
   * Returns the function name without parentheses.
   *
   * @param {string} functionCompleteName
   * @return {*}  {string}
   * @memberof ClientClickDirective
   */
  getOnClientClickFunctionName(functionCompleteName: string): string {
    return functionCompleteName
      .slice(0, functionCompleteName.indexOf('('))
      .trim();
  }

  /**
   * Validates if the onClientClick function has a 'return'.
   *
   * @return {*}  {boolean}
   * @memberof ClientClickDirective
   */
  onClientClickHasReturn(): boolean {
    return this.onClientClick?.trim().toLowerCase().includes('return');
  }

  /**
   * Returns a params collection based on the function name.
   *
   * @param {string} func
   * @return {*}  {string[]}
   * @memberof ClientClickDirective
   */
  getFunctionParams(func: string): string[] {
    let params: string[] = [];
    /* c8 ignore else */
    if (func.includes('(') && func.includes(')')) {
      params = func
        .slice(func.indexOf('(') + 1, func.indexOf(')'))
        .split(',')
        .map((param) => {
          return param.trim().replace(/'/, '');
        });
      return params;
    }
    return params;
  }

  /**
   * Changes 'this' to the correct context if it is defined in the function params.
   *
   * @param {string[]} params
   * @param {*} context
   * @return {*}  {any[]}
   * @memberof ClientClickDirective
   */
  setThisContext(params: string[], context: any): any[] {
    return params.map((param) => {
      /* c8 ignore else */
      if (param === 'this') {
        return context;
      }
      return param;
    });
  }

  /**
   * Triggers the internal Click event mechanism.
   * This mechanism allows the Button to trigger the DataList's OnItemCommand and the Grid's OnRowCommand events.
   *
   * @memberof ClientClickDirective
   */
  triggerClickedInternal(): void {
    const clientClickArgs = {
      CommandName: this.commandName,
      CommandArgument: this.commandArgument,
      CommandSource: this.model
    };
    this.internalEventHandler.onButtonClickEmit({
      clientClickArgs,
      id: this.model.id
    });
  }

  /**
   * Triggers the Click depending on the host component (Button/LinkButton).
   *
   * @param {*} event
   * @memberof ClientClickDirective
   */
  triggerClick(event: any): void {
    /* c8 ignore else */
    if (this.linkbuttonComponent) {
      this.linkbuttonComponent.click(event);
    } else if (this.buttonComponent) {
      this.buttonComponent.click(event);
    }
  }
}

results matching ""

    No results matching ""