Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Custom Component] - Is it possible to access the current instance of the Formio Component within the custom component? #1023

Open
dinbtechit opened this issue Oct 23, 2023 · 16 comments
Assignees
Labels

Comments

@dinbtechit
Copy link

dinbtechit commented Oct 23, 2023

Is it possible to access the current instance of the Formio Component within the custom component?

export class My CustomComponent implements FormioCustomComponent<string> {
  @Input() value: string;
  @Output() valueChange: EventEmitter<string> = new EventEmitter<string>();
  @Output() formioEvent: EventEmitter<FormioEvent> = new EventEmitter<FormioEvent>();
  
  customFunction() {
 
      //  I need to access the instance of Formio Component here.
   }  
 
}

I would like to access the component because the customOptions are not accessible during initialization. Furthermore, dragging the component does not preserve any of the customOptions.

@adhonay
Copy link

adhonay commented Dec 14, 2023

I had this question too, and no one answered.

The solution I came up with was to create a global service, and within it there are methods for adding and viewing the main instance.

In the formiobasecomponent component within the createRenderer function, I called the add method of the service I created.

  createRenderer() {
    const Renderer = this.getRenderer();
    const form = (new Renderer(
      this.formioElement ? this.formioElement.nativeElement : null,
      this.form,
      this.getRendererOptions()
    ));

    // adicionado-inicio
    this.formFormioService.setEstruturaComponenteFormularioRender(form);
    // adicionado-fim

    return form.instance;
  }

In custom components, I injected this global service and viewed the instance that way.

It worked, I hope it helps you.

@pradeepsonisoni
Copy link

Can you explain more @adhonay how you are storing this and how you will get the same instance? It will be very helpful.

@adhonay
Copy link

adhonay commented Dec 15, 2023

Você pode explicar mais@adhonaycomo você está armazenando isso e como obterá a mesma instância? Será muito útil.

Ignore the main and secondary instance part, in your case it will probably only be 1 instance.
I did it this way, because I am using modals from one instance within another.

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { ConstantesSistemaFormio } from '../constantes/constantes-sistema-formio';

@Injectable({
  providedIn: 'root'
})
export class FormFormioService {

  private estruturaComponenteFormularioRenderInstanciaPrincipal = new BehaviorSubject<object>(undefined);
  private estruturaComponenteFormularioRenderInstanciaSecundariaGrid = new BehaviorSubject<object>(undefined);

  constructor() { }

  private quantidadeInstaciasFormioRender(): number {
    return document.querySelectorAll(ConstantesSistemaFormio.tceFormio)?.length;
  }

  public existeInstanciaRenderFormio(): boolean {
    return this.quantidadeInstaciasFormioRender() > 0
  }

  public existeInstanciaSecundariaGridAberta(): boolean {
    return this.quantidadeInstaciasFormioRender() === 2
  }

  public setEstruturaComponenteFormularioRender(instancia) {
    if (instancia && this.quantidadeInstaciasFormioRender() <= 1) {
      this.estruturaComponenteFormularioRenderInstanciaPrincipal.next(instancia);
    } else if (instancia && this.quantidadeInstaciasFormioRender() === 2) {
      this.estruturaComponenteFormularioRenderInstanciaSecundariaGrid.next(instancia);
    }
  }
  public getEstruturaComponenteFormularioRenderInstanciaPrincipal(): object {
    return this.estruturaComponenteFormularioRenderInstanciaPrincipal.value;
  }

  public getEstruturaComponenteFormularioRenderInstanciaSecundariaGrid(): object {
    return this.estruturaComponenteFormularioRenderInstanciaSecundariaGrid.value;
  }
}

@pradeepsonisoni
Copy link

Can you show the createRenderer class aswell how you are extending the class.?

@Sahil-Sayyed
Copy link

Você pode explicar mais@adhonaycomo você está armazenando isso e como obterá a mesma instância? Será muito útil.

Ignore the main and secondary instance part, in your case it will probably only be 1 instance. I did it this way, because I am using modals from one instance within another.

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { ConstantesSistemaFormio } from '../constantes/constantes-sistema-formio';

@Injectable({
  providedIn: 'root'
})
export class FormFormioService {

  private estruturaComponenteFormularioRenderInstanciaPrincipal = new BehaviorSubject<object>(undefined);
  private estruturaComponenteFormularioRenderInstanciaSecundariaGrid = new BehaviorSubject<object>(undefined);

  constructor() { }

  private quantidadeInstaciasFormioRender(): number {
    return document.querySelectorAll(ConstantesSistemaFormio.tceFormio)?.length;
  }

  public existeInstanciaRenderFormio(): boolean {
    return this.quantidadeInstaciasFormioRender() > 0
  }

  public existeInstanciaSecundariaGridAberta(): boolean {
    return this.quantidadeInstaciasFormioRender() === 2
  }

  public setEstruturaComponenteFormularioRender(instancia) {
    if (instancia && this.quantidadeInstaciasFormioRender() <= 1) {
      this.estruturaComponenteFormularioRenderInstanciaPrincipal.next(instancia);
    } else if (instancia && this.quantidadeInstaciasFormioRender() === 2) {
      this.estruturaComponenteFormularioRenderInstanciaSecundariaGrid.next(instancia);
    }
  }
  public getEstruturaComponenteFormularioRenderInstanciaPrincipal(): object {
    return this.estruturaComponenteFormularioRenderInstanciaPrincipal.value;
  }

  public getEstruturaComponenteFormularioRenderInstanciaSecundariaGrid(): object {
    return this.estruturaComponenteFormularioRenderInstanciaSecundariaGrid.value;
  }
}

I am not able to get instance when i invoke setInstance(), or either calling createRenderer() from constructor in my custom component using reference from code snippet you provided , so could you please provide your custom component with the proper place where you are getting the instance ? or you can send across the files which have the running code.
(Note: We have tried all possible ways to get instance and we have angular cli 16 as a mandatory platform.)

@Sahil-Sayyed
Copy link

By extending MaterialComponent class i am able to get the instance of the custom component with setInstance() in one project but in another project without using angular material and considering typescript and angular(angular material excluded ) setup, which class i can extend/implement to achieve similar behavior?

@pradeepsonisoni
Copy link

Hi @dinbtechit

Did you find any solution?

@dinbtechit
Copy link
Author

@pradeepsonisoni - I have not. I think the custom component has some issues with the way how it implemented updating the component value. Also, starting from version Formio/angular version 6.0.0 the custom components are being deprecated all together. So it may be worth forking the custom component code and adding it to your own angular project. That way, you will have more control over the code or at least that's what I am going to be doing to fix this issue.

@pradeepsonisoni
Copy link

@dinbtechit Thank you for quick reply.

@adhonay
Copy link

adhonay commented Jan 11, 2024

Você pode mostrar a classe createRenderer também como está estendendo a classe?

createRenderer is a method already implemented by formio itself in the formiobasecomponent.ts component

@pradeepsonisoni
Copy link

@adhonay If you are able to get the instance. you can share the code how you are implementing the FormioCustomComponent class. let us know because We are not getting the instance.

@adhonay
Copy link

adhonay commented Jan 11, 2024

@adhonaySe você conseguir obter a instância. você pode compartilhar o código como está implementando a classe FormioCustomComponent . deixe-nos saber porque não estamos recebendo a instância.

FormioCustomComponent here is a simple interface, created in the Angular template.

export interface  FormioCustomComponent<T> {
  value: T; // Should be an @Input
  valueChange: EventEmitter<T>; // Should be an @Output
  disabled: boolean;
  formioEvent?: EventEmitter<FormioEvent>; // Should be an @Output
}

You don't need anything more than:

1- Create the service as I sent above.

2- Insert the line below into the createRenderer function in formiobasecomponent.ts to send the instance.
this.formFormioService.setEstruturaComponenteFormularioRender(form);

3- In your CustomComponent, inject the service into the constructor and then wherever you want in the component, use the line:
let instanciaRender = this.formFormioService.getEstruturaComponenteFormularioRenderInstanciaPrincipal();

@pradeepsonisoni
Copy link

pradeepsonisoni commented Jan 11, 2024

@adhonay If we have two instance of the same custom component. Is it working with two instance? I don't think so.

@dinbtechit
Copy link
Author

dinbtechit commented Jan 11, 2024

I had this question too, and no one answered.

The solution I came up with was to create a global service, and within it there are methods for adding and viewing the main instance.

In the formiobasecomponent component within the createRenderer function, I called the add method of the service I created.

  createRenderer() {
    const Renderer = this.getRenderer();
    const form = (new Renderer(
      this.formioElement ? this.formioElement.nativeElement : null,
      this.form,
      this.getRendererOptions()
    ));

    // adicionado-inicio
    this.formFormioService.setEstruturaComponenteFormularioRender(form);
    // adicionado-fim

    return form.instance;
  }

In custom components, I injected this global service and viewed the instance that way.

It worked, I hope it helps you.

@adhonay - isn't the formiobasecomponent class part the npm package, how did you manage to update the createRenderer() method to inject the code - > this.formFormioService.setEstruturaComponenteFormularioRender(form);?

@adhonay
Copy link

adhonay commented Jan 11, 2024

I had this question too, and no one answered.
The solution I came up with was to create a global service, and within it there are methods for adding and viewing the main instance.
In the formiobasecomponent component within the createRenderer function, I called the add method of the service I created.

  createRenderer() {
    const Renderer = this.getRenderer();
    const form = (new Renderer(
      this.formioElement ? this.formioElement.nativeElement : null,
      this.form,
      this.getRendererOptions()
    ));

    // adicionado-inicio
    this.formFormioService.setEstruturaComponenteFormularioRender(form);
    // adicionado-fim

    return form.instance;
  }

In custom components, I injected this global service and viewed the instance that way.
It worked, I hope it helps you.

@adhonay - isn't the formiobasecomponent class part the npm package, how did you manage to update the createRenderer() method to inject the code - > this.formFormioService.setEstruturaComponenteFormularioRender(form);?

I cloned the git project and started implementing custom components from it.

You can modify the createRenderer method because you have direct access to it.

https://github.com/formio/angular/blob/master/projects/angular-formio/src/FormioBaseComponent.ts

Line 108

@dinbtechit
Copy link
Author

Thanks @adhonay, that makes sense now. Actually, a better approach would be to fork the custom component and modify the logic there.

https://github.com/formio/angular/tree/5.5.x/projects/angular-formio/src/custom-component

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants