Components: Feature: Allow user to provide bindings for a ComponentPortal

Created on 18 Jun 2016  路  3Comments  路  Source: angular/components

Bug, feature request, or proposal: feature

What is the expected behavior?

A user can provide optional ResolvedReflectiveProvider[] to the constructor of ComponentPortal, this is a good way to provide data for dialogs.

What is the current behavior?

The component type in ComponentPortal use the injector of the ViewContainerRef.
Dialog must use a service to get data from the application.

Before creating the component in DomPortalHost create a child injector with the bindings:

  /** DomPortalHost **/
  /** Attach the given ComponentPortal to DOM element using the ComponentResolver. */
  attachComponentPortal(portal: ComponentPortal): Promise<ComponentRef<any>> {
    if (portal.viewContainerRef == null) {
      throw new MdComponentPortalAttachedToDomWithoutOriginError();
    }

    return this._componentResolver.resolveComponent(portal.component).then(componentFactory => {
      const childInjector = ReflectiveInjector
        .fromResolvedProviders(portal.bindings,  portal.viewContainerRef.parentInjector);

      let ref = portal.viewContainerRef.createComponent(
          componentFactory, portal.viewContainerRef.length, childInjector);

      let hostView = <EmbeddedViewRef<any>> ref.hostView;
      this._hostDomElement.appendChild(hostView.rootNodes[0]);
      this.setDisposeFn(() => ref.destroy());
      return ref;
    });
  }


/** ComponentPortal **/
/**
 * A `ComponentPortal` is a portal that instantiates some Component upon attachment.
 */
export class ComponentPortal extends Portal<ComponentRef<any>> {
  /** The type of the component that will be instantiated for attachment. */
  public component: Type;

  public bindings: ResolvedReflectiveProvider[];

  /**
   * [Optional] Where the attached component should live in Angular's *logical* component tree.
   * This is different from where the component *renders*, which is determined by the PortalHost.
   * The origin necessary when the host is outside of the Angular application context.
   */
  public viewContainerRef: ViewContainerRef;

  constructor(component: Type, viewContainerRef: ViewContainerRef = null,
              bindings: ResolvedReflectiveProvider[] = null) {
    super();
    this.component = component;
    this.viewContainerRef = viewContainerRef;
    this.bindings = Array.isArray(bindings) ? bindings : [];
  }
}

Most helpful comment

How injector helps to provide inputs of the component?

I understand how I can provide data with custom injection token. But I will have to obtain this data by DI (using created token), but not inputs of the component.

What I am missing? Does injector store information about inputs too?

With that thoughts in mind (custom injection token) this question comes to the mind: how providing data via injection token (through custom injector + DI in dynamically created component) differs from passing data via service (like author used initially)?

UPD:

Ok, possible workaround are:

  1. User injector + custom injection token
  2. Using TemplateRef + TemplatePortal (+ specifying data through actual inputs in template) instead of ComponentPortal
  3. Using service
  4. ...

All of this ways are not looking good solutions for simple providing inputs for dynamically created components using CDK.

FYI @jelbourn

All 3 comments

My PR #761 lets you pass an Injector instance to let you configure what's available to the component. Beyond that, the thinking is that you can set stuff directly to the component instance once you've created it.

How injector helps to provide inputs of the component?

I understand how I can provide data with custom injection token. But I will have to obtain this data by DI (using created token), but not inputs of the component.

What I am missing? Does injector store information about inputs too?

With that thoughts in mind (custom injection token) this question comes to the mind: how providing data via injection token (through custom injector + DI in dynamically created component) differs from passing data via service (like author used initially)?

UPD:

Ok, possible workaround are:

  1. User injector + custom injection token
  2. Using TemplateRef + TemplatePortal (+ specifying data through actual inputs in template) instead of ComponentPortal
  3. Using service
  4. ...

All of this ways are not looking good solutions for simple providing inputs for dynamically created components using CDK.

FYI @jelbourn

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

savaryt picture savaryt  路  3Comments

kara picture kara  路  3Comments

Hiblton picture Hiblton  路  3Comments

jelbourn picture jelbourn  路  3Comments

MurhafSousli picture MurhafSousli  路  3Comments