Angular CDK: Как установить Входы в ComponentPortal

Я хотел бы использовать новый портал из материала CDK для добавления динамического содержимого в несколько частей формы.

У меня сложная структура формы, и цель состоит в том, чтобы иметь форму, указывающую несколько мест, где подкомпоненты могут (или нет) внедрять шаблоны.

Может быть, CDK Portal - не лучшее решение для этого?

Я пытался что-то, но я уверен, что это не так: https://stackblitz.com/edit/angular-yuz1kg

Я пробовал также с new ComponentPortal(MyPortalComponent) но как мы можем установить входы на него? Обычно это что-то вроде componentRef.component.instance.myInput

Ответ 1

Вы можете создать собственный инжектор и внедрить его в созданный вами портал компонентов. -

createInjector(dataToPass): PortalInjector {
    const injectorTokens = new WeakMap();
    injectorTokens.set(CONTAINER_DATA, dataToPass);
    return new PortalInjector(this._injector, injectorTokens);
  }

CONTAINER_DATA - это пользовательский инжектор (InjectorToken), созданный -

export const CONTAINER_DATA = new InjectionToken<{}>('CONTAINER_DATA');

Чтобы потреблять созданный инжектор, используйте -

    let containerPortal = new ComponentPortal(ComponentToPort, null, this.createInjector({
          data1,
          data2
        }));

   overlay.attach(containerPortal);

оверлей является экземпляром OverlayRef (который является порталом выхода)

Внутри "ComponentToPort" вам нужно будет ввести созданный инжектор -

@Inject(CONTAINER_DATA) public componentData: any

Подробнее об этом здесь -

  1. https://github.com/angular/material2/issues/8322

  2. https://github.com/angular/material2/issues/8322

Ответ 2

Вы можете ввести данные в ComponentPortal с помощью специального инжектора, переданного в 3-м параметре ComponentPortal (исправить проблему синтаксиса: невозможно разрешить все параметры для компонента: ([объект объекта], [объект объекта],?).

export const PORTAL_DATA = new InjectionToken<{}>('PortalData');

class ContainerComponent {
  constructor(private injector: Injector, private overlay: Overlay) {}

  attachPortal() {
    const componentPortal = new ComponentPortal(
      ComponentToPort,
      null,
      this.createInjector({id: 'first-data'})
    );
    this.overlay.create().attach(componentPortal);
  }

  private createInjector(data): PortalInjector {

    const injectorTokens = new WeakMap<any, any>([
      [PORTAL_DATA, data],
    ]);

    return new PortalInjector(this.injector, injectorTokens);
  }
}

class ComponentToPort {
  constructor(@Inject(PORTAL_DATA) public data ) {
    console.log(data);
  }
}

Ответ 3

Можно установить компонентные входы (или привязать к выходам как наблюдаемые) следующим образом:

portal = new ComponentPortal(MyComponent);
this.portalHost = new DomPortalHost(
      this.elementRef.nativeElement,
      this.componentFactoryResolver,
      this.appRef,
      this.injector
    );

const componentRef = this.portalHost.attach(this.portal);
componentRef.instance.myInput = data;
componentRef.instance.myOutput.subscribe(...);
componentRef.changeDetectorRef.detectChanges();