Hello ABP Team,
I am working with ABP extensible forms, and I’m using a custom template/component to override the rendering of certain fields via the [templates] property on <abp-extensible-form>. My custom component injects the field config and record data using:
constructor(
  @Inject(EXTENSIONS_FORM_PROP) public prop: FormProp,
  @Inject(EXTENSIONS_FORM_PROP_DATA) public propData: any
) {}
My issue/question:
- When using the default ABP rendering, the options function for typeahead and other extensible fields receives a rich PropDataobject (withrecordand sometimes helpers likegetInjected).
- However, in my custom template component, propDatais just the record (row/entity) and does not include any extra context or helper functions.
- This means that my field’s optionsfunction has less information than it does in the default scenario.
Questions:
- Is there a supported way to access the full PropData(with helpers and full context) inside a custom template/component (e.g., for use in options or validators)?
- Is it possible to have EXTENSIONS_FORM_PROP_DATAprovide the full context instead of only therecordwhen using template overrides?
- If not, is there a recommended pattern to pass additional context to custom field templates, so options/validators can use other injected services or helpers as in the default renderer?
- Are there plans to support this use-case in a future version?
Any best practices, workarounds, or guidance would be greatly appreciated.
Thank you!
@Component({
  selector: 'custom-typeahead-field',
  template: ` ... `
})
export class CustomTypeaheadFieldComponent {
  constructor(
    @Inject(EXTENSIONS_FORM_PROP) public prop: FormProp,
    @Inject(EXTENSIONS_FORM_PROP_DATA) public propData: any
  ) {}
  // ...
  
    search = (params: PagedAndSortedResultRequestDto): Observable<PagedResultDto<any>> => {
        if (this.prop?.options) {
          return this.prop.options(this.propData, params).pipe(
            switchMap((result: any) => {
              if (Array.isArray(result)) {
                return of({ items: result, totalCount: result.length });
              }
              return of(result);
            })
          );
        }
        return of({ items: [], totalCount: 0 });
      };
}
  {
    type: ePropType.Typeahead,
    name: 'propId',
    displayName: 'propName',
    validators: () => [],
    options: (data$, params) => {
      const manufacturerService = data$.getInjected(MyService);
      return myService
        .getList({
          filter: params ?? '',
          maxResultCount: params?.maxResultCount,
          skipCount: params?.skipCount,
        })
        .pipe(
          map(result => {
            //add empty value
            return result.items.map(item => ({ value: item.id, key: item.name }));
          })
        );
    },
    template: MyWrapperComponent,
  },
**ERROR TypeError: data$.getInjected is not a function**
Thank you, David Simões
1 Answer(s)
- 
    0Hello David, Thank you for the detailed ticket and context around your use of custom templates with the extensible forms. Let me address your questions as well. When using custom components inside extensible forms or tables, the injected EXTENSIONS_FORM_PROP_DATAonly provides the plainrecordby default, not the fullPropDatawith helpers likegetInjected.Although PropDatadefinesgetInjected(...), it's only populated in certain rendering contexts (e.g., the default ABP flow). When creating custom components, this context isn’t automatically passed.If you're overriding rendering via custom components (like template: MyComponentinside prop config), you're responsible for providing the full context (record + helpers) if needed.{ provide: EXTENSIONS_FORM_PROP_DATA, deps: [Injector], useFactory: (injector: Injector) => ({ record, getInjected: <T>(token: any) => injector.get<T>(token) }) }As for future support, we’ll share feedback with the team — but for now, the pattern above is the recommended way to ensure full context is available in custom components. I am also sharing a sample project showing how I replicated your structure based on these details: https://drive.google.com/file/d/1qLoFopObla_kGQ1k_a71KVvrlMZ_DPBc/view?usp=drive_link If you think that this does not answer your question, I can assist you further. Thank you for your cooperation. 
 
                                