6

I have the following template for the root component of my angular2 app:

<main class="main">
  <div class="main__container">
    <div class="main__left-area">
      <router-outlet name="left-zone"></router-outlet>
    </div>
    <div class="main__right-area">
      <router-outlet name="right-zone"></router-outlet>
    </div>
  </div>
</main>

And the following routes:

import { HomeSummaryComponent } from "../components/home-summary/home-summary.component"
import { DataSummaryComponent } from "../components/data-summary/data-summary.component"
import { AskSummaryComponent } from "../components/ask-summary/ask-summary.component"

import { Routes } from "@angular/router"

export const AppRoutes: Routes = [
  {
    path: "",
    component: HomeSummaryComponent,
    outlet: "left-zone"
  },
  {
    path: "",
    component: DataSummaryComponent,
    outlet: "right-zone"
  }
];

It actually works pretty well, but I'd like to be able to load more than a single component in the "right-zone" (and in the left one as well actually). The idea would be to have something like this:

{
  path: "",
  components: [ DataSummaryComponent, AskSummaryComponent ],
  outlet: "right-zone"
}

The controllers would just be appended one after one. Is it currently supported? If no, is it possible to extend the existing RouterOutlet to do so?

Thanks

ssougnez
  • 5,315
  • 11
  • 46
  • 79
  • Could you just route to a component that contains both components? FYI, I came up with a way to load HTML fragments into a component such that I can display all kinds of messages, confirmations, etc. without having to create a component for every one. You can even feed them data, even though they're not templates. May get poo poo'd by strict angular folks but not providing ng-include was a pretty big omission to me. For all I know they fixed it and I just don't know it, but I haven't seen it. Anyway, go to http://www.tcoz.com/#/errata and look for "ng-include in Angular 2?" if interested. – Tim Consolazio Feb 28 '17 at 19:03
  • @TimConsolazio see my answer to Madhu Ranjan – ssougnez Feb 28 '17 at 19:07
  • Right, but in addition, you may not want to bother creating another component. You might just want to load an HTML fragment into a template and feed it data (or not, it works great for static stuff). Bring back ng-include! – Tim Consolazio Feb 28 '17 at 19:08

1 Answers1

8

Only one component can be assigned with a Route, What you may do is add a parent component consisting of DataSummaryComponent & AskSummaryComponent and configure it in the route.

Update:

As mentioned in comment you may create a generic component which loads components dynamically using data property configuration in route,

Route configuration

const appRoutes: Routes = [
  { path: '',   redirectTo: '/route1', pathMatch: 'full' },
  { path: 'route1',  component: MasterComponent, data: {puppets : [PuppetComponent1]} },
  { path: 'route2',  component: MasterComponent,  data: {puppets : [PuppetComponent2, PuppetComponent3]}},
  { path: 'route3',  component: MasterComponent,  data: {puppets : [PuppetComponent1, PuppetComponent2, PuppetComponent4]}}
];

Master Component

@Component({
  template: `<h1>I am the Master of components</h1>
  <hr />
  <div #puppetContainer></div>
  `
})
class MasterComponent { 
   @ViewChild('puppetContainer', { read: ViewContainerRef }) puppetContainer: ViewContainerRef;

    constructor(
        private router: Router,
        private route: ActivatedRoute,
        private _componentFactoryResolver: ComponentFactoryResolver,
        private viewContainer: ViewContainerRef) {

    }

    ngOnInit(){
       this.route.data
           .subscribe(data => {
              if(!!data && !!data.puppets && data.puppets.length > 0){
                data.puppets.map(puppet => {
                  let componentFactory = this._componentFactoryResolver.resolveComponentFactory(puppet);
                  this.puppetContainer.createComponent(componentFactory);
                });
              }
           });
    }

}

Check this Plunker!!

Hope this helps!!

Madhu Ranjan
  • 17,334
  • 7
  • 60
  • 69
  • I actually hoped that I wouldn't have to do this. Indeed, the idea is to have a page template composed of two zones and the routes configuration would indicate to angular what components to display on a page. Here, I want to display AskSummaryComponent and DataSummaryComponent but I could have another page with two different components (or three or only one, etc,...) without having to rely every time on an another component that would aggregate them. – ssougnez Feb 28 '17 at 19:06
  • you may make parent component generic driven by route data property to load different components. this way you may have flexibility while configuring routes. Cheers!! – Madhu Ranjan Feb 28 '17 at 19:11
  • Yeah check out my ng-include approximation. In fact I have to update that article with how to feed a fragment data (you basically just put a div with either a class or id that is selectable in the fragment, then in the component loading the fragment, in ngOnViewChecked, select the element with document.querySelector ( 'my-class-or-id' ), and load up the inner html with an ES6 template, e.g. `
    Price: ${data.price}
    `. Saves you from the "thousands of components" problem, and personally I hate fiddling with that complicated and cryptic router.
    – Tim Consolazio Feb 28 '17 at 19:12
  • @ssougnez: Updated answer with Plunker example. Cheers!! – Madhu Ranjan Feb 28 '17 at 19:59
  • Hi, I'm not on my laptop right now but your answer is probably what I was looking for (well at least, a very interesting alternative). I'll accept the answer as soon as I tested it. Thanks – ssougnez Feb 28 '17 at 20:40
  • How could one use this example with the token PuppetComponent1 as a string first, then resolved to a token before it is sent in data: array to master component. – SoEzPz Dec 06 '17 at 16:37
  • 1
    @SoEzPz, Not sure what you mean by resolving to a token, But if you want to pass a component selector as string, and Load it back in component you can do it.. , But you would need to know the Module in which component is and then Load that Module and then search using selector in the loaded module., Check this SO, https://stackoverflow.com/questions/39020164/load-component-dynamically-in-angular-2-using-selector – Madhu Ranjan Dec 06 '17 at 22:39