formio / formio.js

JavaScript powered Forms with JSON Form Builder
https://formio.github.io/formio.js
MIT License
1.88k stars 1.06k forks source link

[ASK] Injecting a service for extended button component #2562

Closed dorianEXOR closed 8 months ago

dorianEXOR commented 4 years ago

Hello guys,

I am currently trying to extend the base button component of FormioJs (https://github.com/formio/formio.js?files=1)

to overwrite certain functions and to use a service as an injectable. But the injection doesn't succeed.

This is my simple service class:

import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { first, tap } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: "root"
})
export default class ButtonService {

  constructor(private http: HttpClient) { }

  getURL(url: any) : Observable<any> {
    return this.http.get(url, { withCredentials: true })
      .pipe(first(), tap(res => { console.log("Got It") }));
  }

  postURL(url: any, submission: any) : Observable<any> {
    return this.http.post(url, submission, { withCredentials: true })
      .pipe(first(), tap(res => { console.log("Posted It") }));
  }
}

The service is always undefined no matter how I approach the injection: the classic way using the module providers array or the following approach.

import ButtonComponent from 'formiojs/components/button/Button';
import buttonEditForm from './ExtendedButton.form'
import ButtonService from '../../services/button.service'

export default class ExtendedButtonComponent extends ButtonComponent {
  constructor(component, options, data, private service: ButtonService) {
    super(component, options, data)
    console.log(service)
  }
  // ... define schema and editForm here ...
onClick() {
// ... overwrite functionality of button onClick() method ...
}

I have also tried @Inject() but this didn't work as well. I was wondering if maybe the inheritance of the base component might be a problem. That's because I had to use a workaround to access the inherited members of the base class (otherwise I would have had to declare them separately).

It looks like this:

let _this = this as ButtonComponent;

Later on, I overwrite the button component with this code:

AllComponents.button = ExtendedButtonComponent;
Components.setComponents(AllComponents);

I was able to overwrite the functionality and the button is also overwritten in the Formbuilder, owing to the workaround I used. But I didn't find a way to access the service.

Node: 10.19.0
OS: win32 x64
Angular: 8.2.14
@angular-devkit/core               8.3.20
@angular-devkit/schematics         8.3.20
@angular/cli                       8.3.20
@ngtools/webpack                   8.3.25
@schematics/angular                8.3.20
@schematics/update                 0.803.20
ng-packagr                         5.7.1
rxjs                               6.4.0
typescript                         3.5.3
webpack                            4.39.2

Best regards, Dorian

travist commented 4 years ago

Since the core renderer is not an Angular component, if you need to inject an external service into your extended ButtonComponent, you will need to hook into the creation of that component to perform the injection. The easiest way to do this is to introduce a new "option" that will be added to the renderer and then the button component can use its options to gain access to it. This will look as follows.

import { Component, AfterViewInit, ViewChild } from '@angular/core';
import ButtonService from '../../services/button.service'

@Component({
  selector: 'app-formview',
  templateUrl: '<formio src="https://examples.form.io/example" [renderOptions]="formioOptions"></formio>'
})
export class AppFormViewComponent implements AfterViewInit {
  public formioOptions = {};
  constructor(private service: ButtonService) {
    formioOptions.buttonService = service;
  }
}

Then in your component you can do as follows.

import ButtonComponent from 'formiojs/components/button/Button';
import buttonEditForm from './ExtendedButton.form';

export default class ExtendedButtonComponent extends ButtonComponent {
  constructor(component, options, data) {
    super(component, options, data)
    console.log(options.buttonService);
  }

  onClick() {
    this.options.buttonService.onClick();
  }
}
dorianEXOR commented 4 years ago

Thank you, this helped me a lot.

Best regards, Dorian

VikkiAlenn commented 8 months ago

Closing this thread as it is outdated. Please re-open if it is still relevant. Thank you for your contribution!