2

I have problem with pass data to router outlet. Usually I do something like below:

<router-outlet (activate)="setConfig($event)"></router-outlet>

and

setConfig(component: { [key: string]: any }) {
   component.data = this.data;
}

and it works perfect.

But problem is when I have multiply router-outlet with empty path and name. So in routing.module I have:

  {
    path: 'test',
    component: TestComponent,
    children: [
      {
        path: '',
        loadChildren: () => loadRemoteModule({
          remoteName: 'test1',
          remoteEntry: `/c/test1/remoteEntry.js`,
          exposedModule: 'Test1Module',
        }).then(m => m.Test1Module)
      },
      {
        path: '',
        outlet: 'test2',
        loadChildren: () => loadRemoteModule({
          remoteName: 'test2',
          remoteEntry: `/c/test2/remoteEntry.js`,
          exposedModule: 'Test2Module',
        }).then(m => m.Test2Module)
      }
    ]
  },

and in component:

<router-outlet (activate)="setConfig($event)"></router-outlet>
<router-outlet (activate)="setConfig($event)" name="test2"></router-outlet>

In this case I can't set component.data = this.data, because when I console.log component inside setConfig it isn't my component from child route as I expected, it is "ɵEmptyOutletComponent", and I don't know how to pass data to this component in this case.

Test1 and Test2 are microfrontends, there are independents projects and there arent't part of project where Test Component is.

emka26
  • 433
  • 1
  • 11
  • 28
  • I think you should use a Subject instead to pass data between your parent and child components involving router outlets. I don't think router outlets are supposed to emit values... – Julius Bryan Mar 30 '22 at 00:23

1 Answers1

0

when I console.log component inside setConfig it isn't my component from child route as I expected, it is "ɵEmptyOutletComponent"

That's because there is no component provided in the children route:

children: [
      {
        path: '',
        loadChildren: () => loadRemoteModule({
          remoteName: 'test1',
          remoteEntry: `/c/test1/remoteEntry.js`,
          exposedModule: 'Test1Module',
        }).then(m => m.Test1Module),
        // component: myComponent   <======= MISSING HERE
      }
]

Of course you don't need to provide one since you only want to lazy load the module.

Instead of assigning the data to the component via activate EventEmitter, you should create a service that can store the data. This way, any of your components can have access to it.


share-data.service.ts (which stores the data)

import { Injectable } from '@angular/core';

import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ShareDataService {

  // This is the data to be shared by components which
  // includes Test component, Test1 component, Test2 component, etc.
  // BehaviorSubject is better then Subject because it will
  // send the last known value even if the subscriber subscribe late.

  public data = new BehaviorSubject<string>('');

  constructor() {}
}

test.component.ts ( which assigns new value to the data)

import { Component } from '@angular/core';
import { ShareDataService } from './share-data.service';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css'],
})
export class TestComponent implements OnInit {
  constructor(private readonly _serv: ShareDataService) {}

  public ngOnInit() {

    // We want to broadcast the new value to the
    // service so all other component can be notify
    // if they are subscribed to the share-data service.

    this._serv.data.next('new data!');
  }
}

test1.component.ts (which fetches the new value from the data)

import { Component, OnInit } from '@angular/core';
import { ShareDataService } from './share-data.service';

@Component({
  selector: 'app-test1',
  templateUrl: './test1.component.html',
  styleUrls: ['./test1.component.css'],
})
export class Test1Component implements OnInit {
  private _myData: string;
 
  constructor(private readonly _serv: ShareDataService) {}

  public ngOnInit() {

    // We pull data from the service and assign the value to the _myData.
    // The subscribe part is to make sure we pull the latest value.

    this._serv.data.subscribe(data => this._myData = data);
  }
}
skouch2022
  • 956
  • 1
  • 3
  • 13
  • But Test1 and Test2 are microfrontends... So there are independents projects, not part of project when Test Component is. – emka26 Mar 30 '22 at 05:23
  • @emka26 You will need to create another micro project that will host the `share-data.service.ts`. Then you need to add a bit of config to both the shell and mfe1 `webpack.config.js` file. The bottom line is that you will need a service to share the data. Here is the link to the tutorial on how to share a service between micro projects: https://github.com/angular-architects/module-federation-plugin/blob/12.0.0/libs/mf/tutorial/tutorial.md#:~:text=Step%205%3A%20Share%20a%20Library%20of%20Your%20Monorepo – skouch2022 Mar 30 '22 at 14:20