Просмотр исходного кода

refactor(admin-ui): Refactor React form input code

Michael Bromley 2 лет назад
Родитель
Сommit
5f9b435bc8

+ 10 - 7
packages/admin-ui/src/lib/core/src/providers/component-registry/component-registry.service.ts

@@ -1,25 +1,28 @@
-import { Injectable, InjectionToken, Type } from '@angular/core';
+import { Injectable, Provider, Type } from '@angular/core';
 
 import { FormInputComponent } from '../../common/component-registry-types';
 
-export const INPUT_COMPONENT_OPTIONS = new InjectionToken<{ component?: any }>('INPUT_COMPONENT_OPTIONS');
-
 @Injectable({
     providedIn: 'root',
 })
 export class ComponentRegistryService {
-    private inputComponentMap = new Map<string, { type: Type<FormInputComponent<any>>; options?: any }>();
+    private inputComponentMap = new Map<
+        string,
+        { type: Type<FormInputComponent<any>>; providers: Provider[] }
+    >();
 
-    registerInputComponent(id: string, component: Type<FormInputComponent<any>>, options?: any) {
+    registerInputComponent(id: string, component: Type<FormInputComponent<any>>, providers?: Provider[]) {
         if (this.inputComponentMap.has(id)) {
             throw new Error(
                 `Cannot register an InputComponent with the id "${id}", as one with that id already exists`,
             );
         }
-        this.inputComponentMap.set(id, { type: component, options });
+        this.inputComponentMap.set(id, { type: component, providers: providers || [] });
     }
 
-    getInputComponent(id: string): { type: Type<FormInputComponent<any>>; options?: any } | undefined {
+    getInputComponent(
+        id: string,
+    ): { type: Type<FormInputComponent<any>>; providers: Provider[] } | undefined {
         return this.inputComponentMap.get(id);
     }
 }

+ 7 - 16
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/dynamic-form-input/dynamic-form-input.component.ts

@@ -4,14 +4,13 @@ import {
     ChangeDetectionStrategy,
     ChangeDetectorRef,
     Component,
-    ComponentFactory,
-    ComponentFactoryResolver,
     ComponentRef,
     Injector,
     Input,
     OnChanges,
     OnDestroy,
     OnInit,
+    Provider,
     QueryList,
     SimpleChanges,
     Type,
@@ -37,10 +36,7 @@ import { switchMap, take, takeUntil } from 'rxjs/operators';
 import { FormInputComponent } from '../../../common/component-registry-types';
 import { ConfigArgDefinition, CustomFieldConfig } from '../../../common/generated-types';
 import { getConfigArgValue } from '../../../common/utilities/configurable-operation-utils';
-import {
-    ComponentRegistryService,
-    INPUT_COMPONENT_OPTIONS,
-} from '../../../providers/component-registry/component-registry.service';
+import { ComponentRegistryService } from '../../../providers/component-registry/component-registry.service';
 
 type InputListItem = {
     id: number;
@@ -78,7 +74,7 @@ export class DynamicFormInputComponent
     private listId = 1;
     private listFormArray = new FormArray([] as Array<FormControl<any>>);
     private componentType: Type<FormInputComponent>;
-    private componentOptions?: any;
+    private componentProviders: Provider[] = [];
     private onChange: (val: any) => void;
     private onTouch: () => void;
     private renderList$ = new Subject<void>();
@@ -86,7 +82,6 @@ export class DynamicFormInputComponent
 
     constructor(
         private componentRegistryService: ComponentRegistryService,
-        private componentFactoryResolver: ComponentFactoryResolver,
         private changeDetectorRef: ChangeDetectorRef,
         private injector: Injector,
     ) {}
@@ -96,7 +91,7 @@ export class DynamicFormInputComponent
         const component = this.componentRegistryService.getInputComponent(componentId);
         if (component) {
             this.componentType = component.type;
-            this.componentOptions = component.options;
+            this.componentProviders = component.providers;
         } else {
             // eslint-disable-next-line no-console
             console.error(
@@ -113,14 +108,13 @@ export class DynamicFormInputComponent
 
     ngAfterViewInit() {
         if (this.componentType) {
-            const factory = this.componentFactoryResolver.resolveComponentFactory(this.componentType);
             const injector = Injector.create({
-                providers: [{ provide: INPUT_COMPONENT_OPTIONS, useValue: this.componentOptions }],
+                providers: this.componentProviders,
                 parent: this.injector,
             });
 
             // create a temp instance to check the value of `isListInput`
-            const cmpRef = factory.create(injector);
+            const cmpRef = this.singleViewContainer.createComponent(this.componentType, { injector });
             const isListInputComponent = cmpRef.instance.isListInput ?? false;
             cmpRef.destroy();
 
@@ -132,7 +126,6 @@ export class DynamicFormInputComponent
             this.renderAsList = this.def.list && !isListInputComponent;
             if (!this.renderAsList) {
                 this.singleComponentRef = this.renderInputComponent(
-                    factory,
                     injector,
                     this.singleViewContainer,
                     this.control,
@@ -151,7 +144,6 @@ export class DynamicFormInputComponent
                             if (listItem) {
                                 this.listFormArray.push(listItem.control);
                                 listItem.componentRef = this.renderInputComponent(
-                                    factory,
                                     injector,
                                     ref,
                                     listItem.control,
@@ -254,12 +246,11 @@ export class DynamicFormInputComponent
     }
 
     private renderInputComponent(
-        factory: ComponentFactory<FormInputComponent>,
         injector: Injector,
         viewContainerRef: ViewContainerRef,
         formControl: UntypedFormControl,
     ) {
-        const componentRef = viewContainerRef.createComponent(factory, undefined, injector);
+        const componentRef = viewContainerRef.createComponent(this.componentType, { injector });
         const { instance } = componentRef;
         instance.config = simpleDeepClone(this.def);
         instance.formControl = formControl;

+ 8 - 3
packages/admin-ui/src/lib/react/src/components/react-form-input.component.ts

@@ -1,9 +1,14 @@
-import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
+import { Component, inject, InjectionToken, OnInit, ViewEncapsulation } from '@angular/core';
 import { FormControl } from '@angular/forms';
-import { CustomField, FormInputComponent, INPUT_COMPONENT_OPTIONS } from '@vendure/admin-ui/core';
+import { CustomField, FormInputComponent } from '@vendure/admin-ui/core';
+import { ElementType } from 'react';
 import { ReactComponentHostDirective } from '../react-component-host.directive';
 import { ReactFormInputOptions } from '../types';
 
+export const REACT_INPUT_COMPONENT_OPTIONS = new InjectionToken<{
+    component: ElementType;
+}>('REACT_INPUT_COMPONENT_OPTIONS');
+
 @Component({
     selector: 'vdr-react-form-input-component',
     template: ` <div [vdrReactComponentHost]="reactComponent" [context]="context" [props]="context"></div> `,
@@ -20,7 +25,7 @@ export class ReactFormInputComponent implements FormInputComponent, OnInit {
 
     protected context: ReactFormInputOptions;
 
-    protected reactComponent = inject(INPUT_COMPONENT_OPTIONS).component;
+    protected reactComponent = inject(REACT_INPUT_COMPONENT_OPTIONS).component;
 
     ngOnInit() {
         this.context = {

+ 12 - 2
packages/admin-ui/src/lib/react/src/providers.ts

@@ -9,7 +9,10 @@ import {
     REACT_CUSTOM_DETAIL_COMPONENT_OPTIONS,
     ReactCustomDetailComponent,
 } from './components/react-custom-detail.component';
-import { ReactFormInputComponent } from './components/react-form-input.component';
+import {
+    REACT_INPUT_COMPONENT_OPTIONS,
+    ReactFormInputComponent,
+} from './components/react-form-input.component';
 
 /**
  * @description
@@ -22,7 +25,14 @@ export function registerReactFormInputComponent(id: string, component: ElementTy
         provide: APP_INITIALIZER,
         multi: true,
         useFactory: (registry: ComponentRegistryService) => () => {
-            registry.registerInputComponent(id, ReactFormInputComponent, { component });
+            registry.registerInputComponent(id, ReactFormInputComponent, [
+                {
+                    provide: REACT_INPUT_COMPONENT_OPTIONS,
+                    useValue: {
+                        component,
+                    },
+                },
+            ]);
         },
         deps: [ComponentRegistryService],
     };