16

I have the following jsfiddle

I want to be able to stick my custom component into a specific grid (e.g. "")

Right now without Angular2, I just use:

var el = $.parseHTML("<div><div class=\"grid-stack-item-content\" data-id=\""+id+"\"/><div/>");
this.grid.add_widget(el, 0, 0, 6, 5, true);

The issue is, I have no idea how I could do something like:

var el = $.parseAndCompileHTMLWithComponent("<div><div class=\"grid-stack-item-content\" data-id=\""+id+"\"/><fancy-button></fancy-button><div/>");
this.grid.add_widget(el, 0, 0, 6, 5, true);

In angular1, I know there is a compile, but in angular2, there is no such thing.

My fancy-button component is straightforward and is as follows:

@Component({
  selector: 'fancy-button',
  template: `<button>clickme</button>`
})
export class FancyButton {}

How can I dynamically add the fancy-button component?

Fabio Antunes
  • 22,251
  • 15
  • 81
  • 96
Rolando
  • 58,640
  • 98
  • 266
  • 407

2 Answers2

6

The easist way to add fancy-button component dynamically might be as follows:

1) Add component to entryComponents array of your module

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, GridStackComponent, FancyButtonComponent ],
  entryComponents: [ FancyButtonComponent ], // <== here
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

2) Get root node from compiled component

constructor(private vcRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) { }

getRootNodeFromParsedComponent(component) {
  const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
  const ref = this.vcRef.createComponent(componentFactory, this.vcRef.length, this.vcRef.injector);
  const hostView = <EmbeddedViewRef<any>>ref.hostView;
  return hostView.rootNodes[0];
}

3) Use it anywhere

const fancyBoxElement = this.getRootNodeFromParsedComponent(FancyBoxComponent);  
$('#someId').append(fancyBoxElement);

Here's Plunker Example for your case

If you're looking for something more complicated then there are a lot of answers where you can use angular compiler to do it working

Community
  • 1
  • 1
yurzui
  • 205,937
  • 32
  • 433
  • 399
  • @yuzui I tried this example, I get **this.componentFactoryResolver.resolveComponentFactory is not a function** error – deen Nov 11 '16 at 07:52
  • @rish can you provide some plunker? – yurzui Nov 11 '16 at 08:18
  • @yuzui thnx for reply, https://plnkr.co/edit/EPYcF3qFEkYhc12WVEeD?p=preview – deen Nov 11 '16 at 09:05
  • 1
    @rish If you want create component with dynamic html then you have to use `Compiler`. I updated your plunker https://plnkr.co/edit/GDyJk0GGPOF5opax5cwX?p=preview As you can see i get `HtmlElement` and add it to `document.body` – yurzui Nov 11 '16 at 09:28
  • @yuzui thnx it's really helped me, just one question here, can we create these two methods inside normal class which has no [at]Component and [at]Directives? – deen Nov 11 '16 at 10:00
1

You need to use Angular 2’s ViewContainerRef class, which provides a handy createComponent method. The ViewContainerRef can be informally thought of as a location in the DOM where new components can be inserted.

this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);

Here's a working plunker example.

Or you can use the generic HTML outlete from this post

Community
  • 1
  • 1
tottomotto
  • 2,193
  • 2
  • 22
  • 29
  • There are a lot of DynamicComoponentLoader threads, but those answers are not relevant, because it has been deprecated. – tottomotto Nov 01 '16 at 14:51