8

I have a bunch of static pages that use various components that are placed wherever a HTML designer likes. e.g. within any page on a WordPress site.

Though the sample components shown here are simple Panels, but in reality there are all sorts of components, e.g. Search, Lists, Editors, Views etc...

Currently they have been done on lots of Wordpress Sites where each and every page can have totally different layouts. In the past we used Angular 1.5 where the WP developer you could just put our app tag up near the body and then any widget (we have about 30) could be placed 1 or more times in any page.

Components can be re-used so making the components root components via the bootstrap[] property does not make sense as you can only use a root component once on a page. As seen in my second example.

Technique 1

Here is a screenshot and Plunker for the first setup. Notice that I have 4 area's in which I place 3 components with component 1 being reused.

This Example is done by laying out the components inside a single root component, which is impractical for my use case where Wordpress Pages will have totally different layout and composition requirements. .

Plunkr

enter image description here

Technique 2

I have tried using a technique where each widget is bootstrapped as a root component, based on this post Bootstrapping Multiple Applications Sprinkling Angular 2 components inside a non-angular page.

But when I use this technique the 2nd instance of a widget does not load. AKA widget 1.

Plunkr

See example with bootstrapping

enter image description here

Technique 2 - Has further problems

If you have bootstrapped 3 root components, you MUST use all of them otherwise Angular throws up an error about the root component that you did not use.

Plunker

enter image description here

Technique 3

The use of <ng-content></ng-content> does not seem to work root components.

See: Angular2 Root Component with ng-content

Community
  • 1
  • 1
David Cruwys
  • 6,262
  • 12
  • 45
  • 91

4 Answers4

1

For this kind of widgets the better is to have an ng2 application instantiated per each widget like Bootstrap multiples applications. I did post a possible solution there.

I do implement an ApplicationFactory which create a dynamic selector like:

moduleFactory(selector: string, childModule : ModuleWithProviders) {

  @Component({
    selector, // dynamic selector
   ...
  })
  export class AppComponent implements AfterViewInit{
    constructor(resolver: ComponentFactoryResolver){}
    ngAfterViewInit() {
      // Cretate a Child components dynamic 
      // mapping from childModule::[bootstrap] components decoration
    }
 }

 @NgModule({
   declarations: [
     AppComponent
   ],
   imports: [
     BrowserModule,
     FormsModule,
     HttpModule
   ],
   bootstrap: [AppComponent]
 })
 class AppModule { }

  platformBrowserDynamic()
      .bootstrapModule(AppModule, {providers: childModule.providers});
}

In then in ngAfterViewInit you may create a dynamic component using a ComponentFactoryResolver

This is not an ideal solutions but it works

user55993
  • 311
  • 3
  • 6
0

You can create a bunch of wrapper components with different selectors, each wrapping the same component, and then bootstrap these wrapper components instead.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I have expanded my original post to show how bootstrapping a component to a root component, means that you can only use each component ONCE. – David Cruwys Oct 28 '16 at 05:55
  • That's what I explain in my answer. Create **multiple** wrapper components only for the purpose of wrapping your actual component. Only the selector of the outer-most component matters, you can reuse another component in each of the wrapper components as often as you want. – Günter Zöchbauer Oct 28 '16 at 06:02
  • I don't really understand what your suggesting, I'm wondering if you could alter one of my plunkrs to demonstrate what you mean?. But for your clarity, the static pages I'm talking about are inside WordPress where each and every page can have totally different layouts. In the past we used Angular 1.5 where you could just put your app tag up near the body and then any widget (we have about 30) can be used 1 or more times on any page. – David Cruwys Oct 28 '16 at 06:12
  • If you want bootstrap component A 5 times, you can create component B, C, D, E, F, where each of these 5 components only contains component A. Then bootstrap each B, C, D, E, F. I got the impression the Angular team plans to support bootstrapping a component multiple times eventually. – Günter Zöchbauer Oct 28 '16 at 06:16
  • So your suggestion is that if I have component (A, B, C), I could create wraper (A1, A2, A3, A4, A5) + (B1, B2, B3, B4, B5) + (C1, C2, C3, C4, C5) and in so doing I could give my wordpress guy up to 5 instaces of each of my components (being A,B & C). I guess that would work, but its a pretty dirty solution. – David Cruwys Oct 28 '16 at 06:21
  • 1
    I agree it's dirty but it could get you going until the unerlying issue is fixed. You might also be able to create the components dynamically at runtime to reduce the pain, but I'm not sure, never played with this approach http://stackoverflow.com/questions/34784778/equivalent-of-compile-in-angular-2/37044960#37044960 – Günter Zöchbauer Oct 28 '16 at 06:25
  • 1
    FYI: Just found that this technique can't be used anyway, because if you define multiple root components, you must use ALL of them. They are not optional. I commented in my original post in the area titled "Technique 2 - Has further problems" – David Cruwys Oct 28 '16 at 07:30
0

Could you explain better what you want to achieve? I don't understand you... you don't need to create 4 different components to do what you're doing, you can just do it like this:

https://plnkr.co/pvvlD7O2gXZBjVkY16po?p=preview

<table>
   <tr>
      <td>
          <h2>Area 1</h2>
          <my-widget></my-widget>
      </td>
      <td>
          <h2>Area 2</h2>
          <my-widget [title]="'custom title'"></my-widget>
      </td>
    </tr>
   <tr>
      <td>
          <h2>Area 3</h2>
          <my-widget [background]="'yellow'"></my-widget>
      </td>
      <td>
          <h2>Area 4</h2>
          <my-widget [title]="'Last one'" [background]="'blue'"></my-widget>
      </td>
    </tr>
  </table>
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I'm not trying to paramaterize a simple widget, I've added a not above, that explains. "Even though the sample components shown here are simple Panels, in reality there are all sorts of components, e.g. Search, Lists, Editors, Views etc..." – David Cruwys Oct 28 '16 at 06:08
0

Okay, with you update I got you. I'm not user if there is any way to make work what you're trying but what I'd do is something like this: `

<body>
  <my-app>
    your table code
    </my-app>
  </body>

` and then make you root element 'my-app' template looks like this: ''

'' will bind the html that you put inside 'my-app' so it'll work, and you can use a different content for each static page as you want.

  • The problem with that techique is the area where "your table code" is written, The HTML totally disappears after is parsed by Angular 2. I have looked at using the directive as a potential solution, but I can't seem to get that to work. – David Cruwys Oct 28 '16 at 06:24
  • you're right, I dunno why it's not working in plkr... but I'm using it and works perfectly, here is a test project, which I've public and where I'm using ng-content to create a modal window component: https://bitbucket.org/albertomartineztomas/angular2_test/src/1a54e7ced75fe5b1b00c40b73cf0a04554275c59/src/app/components/containers/modal/modal.html?at=master&fileviewer=file-view-default – Alberto Martinez Oct 28 '16 at 06:29
  • I found out why it does not work, cannot be used for root components, I've listed a link in my original question – David Cruwys Oct 28 '16 at 07:31