Transferring data between a ComponentPortal within an Angular CDK

After attempting to implement the method described in a Stack Overflow thread on Angular CDK: How to set Inputs in a ComponentPortal, I've encountered issues with the deprecated PortalInjector without clear guidance on what to use instead. The deprecation warning simply advises to "Use Injector.create instead," leaving me confused about how and where to apply it and what it's meant to replace.

Additionally, I delved into Material's Dialog component in search of insights on how to handle this, but to no avail.

So, I am presenting my question again in the context of Angular 13:

How can I effectively transfer data in and out of a component created through ComponentPortal()? If the solution involves using an Injector, could you kindly direct me to an example or documentation illustrating the process? Perhaps even a basic 'hello world' example showcasing Injector usage?

Answer №1

It seems I may be a bit behind, but there is a nifty way to utilize @Input() and @Output() of a component within a Portal. It may not be obvious at first glance, but by calling

this.overlayRef.attach(MyComponent)
, you can obtain a ComponentRef<MyComponent>. This allows direct access to the component instance, giving you the flexibility to manipulate it as needed.

Here's an example:

const componentPortal = new ComponentPortal(MyComponent);
const componentRef = this.overlayRef.attach(componentPortal);

// Set input data:
componentRef.instance.someInput = 'test';

// Subscribe to output:
componentRef.instance.someOutput.subscribe();

Your MyComponent would have a structure like this:

@Component({...})
export class MyComponent {
    @Input()
    someInput: string;

    @Output()
    someOutput = new EventEmitter<string>();
}

Keep on coding!

Answer №2

I may be a little fashionably late to the gathering, but here's an alternative approach using the Injector.create method.

To begin, I defined an injection token:

export const CUSTOM_INJECTION_TOKEN = new InjectionToken<string>('CUSTOM_INJECTION_TOKEN');

In my scenario, I have a service responsible for creating and supplying the ComponentPortal. The implementation looks something like this:

export class BarService {
  // ...

  launch(component: ComponentType<any>, info?: unknown) {
    // ...

    const portal = new ComponentPortal(
      component,
      null,
      Injector.create({
        providers: [{ provide: CUSTOM_INJECTION_TOKEN, useValue: info }],
      }),
    );

    // ...
  }
}

Subsequently, I utilized @Inject() to access the information.

export class FoobazComponent {
  constructor(@Inject(CUSTOM_INJECTION_TOKEN) info: MyDataType) { }
}

Finally, when invoking the service to generate the portal, the code resembled the following:

const information = {baz: 'qux'};
barService.launch(FoobazComponent, information);

Answer №3

In my opinion, there isn't a direct method to pass data in and out of the componentportal.

One approach is to send the data you want to use as an @Input through the attached event of the portal.

Take a look at this demo code demonstrating how to pass values to the Guest component.

<ng-template (attached)="onComponentRendering($event)" [cdkPortalOutlet]="guestPortal"></ng-template>

Then, you can access it like this:

 public onComponentRendering(ref): void {
    ref = ref as ComponentRef<any>;
    ref.instance['guestData'] = [ ...something];
 }

For output data, you can establish a service (using Subject) to facilitate communication between components.

Answer №4

My approach was slightly different, especially suitable for small amounts of data. I couldn't use the method suggested by @Shashank Vivek because I initialized the ComponentPortal within a directive.

One alternative is to utilize ReplaySubject. Here is a basic example. First, define it in an Injectable:

@Injectable
myService {
  overlayNotification: ReplaySubject<boolean>;
}

In your Component:

myComponent implements OnInit
constructor(private myService: myService) {}
ngOnInit() {
  this.myService.overlayNotification = new ReplaySubject();
}
method4Overlay() {
  this.myService.overlayNotification.next(.... your data ...);
  this.overlayRef = this.overlay.create(overlayConfig);
  this.overlayRef.attach(new ComponentPortal(MySampleComponent));
}

Lastly, in your MySampleComponent:

MySampleComponent implements OnInit
constructor(private myService: myService) {}
ngOnInit() {
    this.myService.overlayNotification.subscribe((myData:...) => .... received data);
 }

Using ReplaySubject allows for easy updates. Keep in mind that events are not replayed, and you need to create a new instance. This method bypasses the need for @Input().

Further details will require your own coding, but this outline offers an alternative approach.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I encountered an issue while working with Material-UI and Mobx. The error message reads: "Material-UI: capitalize(string) function requires a string argument

enter code hereI encountered this issue when I copied a React component from and the state of this component is managed by Mobx as shown below: @observable snackbarState = { open: false, vertical: null, horizontal: null, }; @action toggle ...

How to Force a jQuery Redraw Following Data Retrieval Using Ajax

Hey everyone, It's been a long time since I started listening, but this is my first post... I have a client who needs a complex feature on their website. They want to merge the content of 3 different pages into one seamless experience for users afte ...

A guide on displaying an array object in a table column using Vue.js and Element UI

Having issues with rendering array data in Vue Js Element UI using the el-table-column element. The string data displays correctly, but I'm facing problems with the array data. I've attempted to include static data within the data() return method ...

Is there a way to extract only the value from the most recent request?

While working with VueJS, I have a handler for changes in an input field that looks like this: inputHandler(url, params){ const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST&ap ...

What is causing my axios request to not retrieve the correct data?

My axios instance is set up to connect to an API that has a login route. When I test the API using Postman, everything works perfectly and it returns JWT access and refresh tokens for valid credentials. However, when I try to login through my app using axi ...

Adding setTimeout within the Axios Scope can enhance the functionality and performance of your

Show an alert in the catch block of Axios. The issue at hand: Error message does not disappear after the specified time when using setTimeout. ...

What steps can be taken to resolve the issue of receiving the error message "Invalid 'code' in request" from Discord OAuth2?

I'm in the process of developing an authentication application, but I keep encountering the error message Invalid "code" in request when attempting to obtain a refresh token from the code provided by Discord. Below is a snippet of my reques ...

Illuminating individual table cells as a user drags their mouse across a row

My goal is to create a feature that allows users to highlight cells in a table by dragging the mouse over them, similar to what is discussed in the question and answer provided here. However, I would like to limit this drag/highlight effect to only span w ...

The 'payload' property is not found within the 'Actions' type

I recently started using TypeScript and Visual Studio Code. I encountered the following issue: *[ts] Property 'payload' does not exist on type 'Actions'. This is my code: action.ts file: import { Action } from '@ngrx/store&apos ...

Performing mathematical calculations with numerical values

This piece of code was created as a component of a calculator project for learning purposes. It functions correctly for the most part. However, I noticed that the addition operation seems to concatenate the two numbers together instead of actually adding ...

Tips for creating Junit tests for a CDK environment

As a newcomer to CDK, I have the requirement to set up SQS infrastructure during deployment. The following code snippet is working fine in the environment: export class TestStage extends cdk.Stage { constructor(scope: cdk.Construct, id: string, props: ...

Using Stack and Drawer Navigations Together in React Native Navigation(v6)

I am looking to merge Stack and Drawer navigations. I have multiple screens and wish to display select screen labels in the drawer tab. <RootNavigatorStack.Navigator> <RootNavigatorStack.Screen name="DrawerTab" component={DrawerNavig ...

Incorporating graphics into a React component

Currently exploring React JS and looking to dive into the practical side of things. Following a documentation tutorial that constructs a basic comment system. I've replicated the component structure outlined in the tutorial: PostBox PostList Pos ...

Creating a dynamic div and populating it with data from various elements in separate xhtml files: a step-by-step guide

I am looking to dynamically add a div under the div tag with id "includedContent" in the code below. Additionally, I would like to modify the load method to accept an array of ids instead of a hardcoded Id(123) and display the data in the dynamically creat ...

Ways to close jQuery Tools Overlay with a click, regardless of its location

I have integrated the Overlay effect from jQuery Tools to my website, with the "Minimum Setup" option. However, I noticed that in order to close it, the user has to specifically target a small circle in the upper right corner which can affect usability. It ...

Using JavaScript to organize and reformat JSON data into grouped structures

In my dataset, I am unable to make any formatting adjustments or modifications. //input json data [ { "Breaks":[ {"points":12,"points_total":12,"average":8.0,"faults":[]}, {"points":17,"points_total":29,"average ...

Scrolling triggers the click event

Within my JavaScript code, I have a rather simple event listener set up to listen for a click: element.addeventlistener('click', ()=>{ #do somthing }) However, I am encountering an issue on IOS (iPhone) where scrolling triggers the event list ...

Utilize JavaScript to extract an image from an external URL by specifying its attributes (id, class)

Is it possible to fetch an image from an external website by using its CSS id or class in conjunction with JavaScript/jQuery's get methods? If so, could someone provide guidance on how to achieve this task? ...

The textbox is only enabled when a specific selection is made in the dropdown menu

My JavaScript code seems to be malfunctioning: <script language="javascript" type="text/javascript"> function ShowExpenseReport(Expense_Report_ID) { var width = screen.width; var leftpad = (width - 740) / 2; var jsopti ...

What's the Deal with Blank Square Brackets in JavaScript?

While browsing through , I stumbled upon this code snippet: useEffect(() => { const interval = setInterval(() => { console.log('This will run every second!'); }, 1000); return () => clearInterval(interval); }, []); I am intri ...