18

I have been trying to find the solution of this problem from two days. Unfortunately, I can not get what I want. I am using Angular5.

<div class="form-group col-md-12" [innerHTML]="GetItemsOfHolder(item.children[1],1,
'UserConfigGroupsLabelHolder') | keepHtml"></div>

This is what my function looks like:

GetItemsOfHolder(item: any,divName:string, recursive: boolean = false,typeName:string="") 
{
return html;
}

Everything works fine, unless The html which I am returning contains one package named Select2 This is what I use to add the html into this div it works very fine. Until I wanted to add the dynamic package.

What I mean is return html contains the package component like this:

itemhtml +="<select2 data-type='"+holderItem.itemType+"' 
[data]='this.dropdownData."+holderItem.name+"'></select2>"  

This just returns the plain text to the browser and doesn't work as expected.

What I want is the string to be turned into component or any other way which works and generates the select2 dropdown.

I have been trying to search so many things.But it doesn't works This is good but I can not understand this And dynamiccomponentloading is deprecated.

Can anyone please give me an idea How can I resolve this problem? Any example would be a great.

Just code
  • 13,553
  • 10
  • 51
  • 93
  • Angular will sanitize pretty much everything so that is why you are getting plain text. What you want to look into is ReflectiveInjector and mainly ComponentFactoryResolver. The main idea is that components need some other info(services, other components, etc) to be rendered, so you use the Injector to get Dependency Injection refs then the Component factory builds your component. You then insert this to a ViewChild reference. There is a more complicated way of dynamically making components that uses the compiler and requires a ModuleWithComponentFactories, this is what angular actually uses. – Devcon Jan 12 '18 at 04:59
  • @Devcon Thanks for the answer, can you give me any example of this? – Just code Jan 12 '18 at 06:04
  • @Justcode This ain't yo'mama´s AngularJS ;D Joking aside, you cannot add new components like in AngularJS watch and weep https://www.youtube.com/watch?v=3yUQz1rYB2c&index=7&list=PLB17qI-lepyhiKF5sy6P46Vqj4crwuoDU – MTJ Jan 12 '18 at 11:28
  • @user1740331 I was able to do this easily before in 1.0 :P any ways thanks for the link. – Just code Jan 12 '18 at 15:42
  • Yeah I know. Tried to formulate an answer but the implementation for this is quite complex and spans multiple files, directives, appModule etc. There is a repository link in the end of the video check it out. – MTJ Jan 12 '18 at 21:39
  • I must be missing something, this sounds like a standard component being passed parameters. Which aspects of the component needs to be dynamic? The template? The component logic? Where is this data/info that the final product is derived from? – ppovoski Jan 12 '18 at 22:16
  • @ppovoski nvm, Its been resolved. I resolved it using the html directive only. I will post answer later. – Just code Jan 13 '18 at 04:00
  • 1
    you can do it with https://angular.io/guide/dynamic-component-loader – nicearma Jan 14 '18 at 22:23
  • You should refer this link https://stackoverflow.com/questions/39678963/load-existing-components-dynamically-angular-2-final-release – hrdkisback Jan 16 '18 at 12:12

3 Answers3

9

As commented by @Devcon

Angular will sanitize pretty much everything so that is why you are getting plain text. What you want to look into is ReflectiveInjector and mainly ComponentFactoryResolver. The main idea is that components need some other info(services, other components, etc) to be rendered, so you use the Injector to get Dependency Injection refs then the Component factory builds your component. You then insert this to a ViewChild reference. There is a more complicated way of dynamically making components that uses the compiler and requires a ModuleWithComponentFactories, this is what angular actually uses.

And searching on the angular, I accept that angular should not be done this way.

As I have to create the fully dynamic page which must be rendered in html. I changed my json little bit and using the ng-container and ng-template and using ngswitch I made recursive call in the template it self and found its working very fine.

I get many advantages using this: The HTML (I render dynamically) itself is in HTML, Code is clean and readable, easily maitainable.

The example given here is pretty much the same I have done. https://stackoverflow.com/a/40530244/2630817

A small example is here:

<ng-template #itemsList let-itemsList>
  <div *ngFor="let item of itemsList;let i = index">
    <div [ngSwitch]="item.itemType">
        <div class="form-group" *ngSwitchCase="'TEXT'">
            <label>
                {{item.label}}
              </label>
              <input id="{{item.name}}" value="{{item.value}}" type='text' class='form-control txtbox ui-autocomplete-input'/>
        </div>
        <div class="form-group" *ngSwitchCase="'PASSWORD'">
            <label>
                {{item.label}}
              </label>
              <input id="{{item.name}}" value="{{item.value}}" type='password' class='form-control txtbox ui-autocomplete-input'/>
        </div>
        <div class="form-group" *ngSwitchCase="'BOOLEAN'">
            <label style='width:40%'>{{item.label}}</label>
            <div class="form-group"><input id="{{item.name}}" type='checkbox' /></div>

        </div>
        <div  class="form-group" *ngSwitchCase="'LABEL'">
            <label class="form-control">{{item.label}}</label>
        </div>
        <div class="form-group"  *ngSwitchDefault>
            <label>
                {{item.label}}
              </label>
              <select2 class="form-control"  [data]="GetDropDowndata(item.holderId)" [cssImport]="false" [width]="300" [options]="GetOptions(item.type)"></select2>
          </div>
    </div>
  </div>

Just code
  • 13,553
  • 10
  • 51
  • 93
  • could you pls provide working stackblitz demo. ? am also in middle of this issue. what am trying is. am getting html template via backend GET method. i need to show select option and input text in my front end. it would so helpful if you share the demo. Thank you – Mr. Learner Mar 14 '19 at 13:58
  • i finally found it cannot be done with input elements as Angular sanitize almost all elements except block level and inline elements. – Mr. Learner Mar 14 '19 at 14:00
  • @worstCoder that's great. its recommended to keep the html in html file. it will be always helpful. – Just code Mar 14 '19 at 16:16
5

You can load every you want in one div, you have to play with ng-template and ng-content.

First you have to create one directive:

import {Directive, ViewContainerRef} from '@angular/core';

@Directive({
  selector: '[dynamic]',
  exportAs: 'dynamicdirective'
})
export class DynamicDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }

}

After you have to put it in some ng-template like:

<p>
  page works!
</p>


<ng-template #sider=dynamicdirective dynamic></ng-template>

and use it like

import {Component, ComponentFactoryResolver, OnInit, ViewChild} from '@angular/core';


@Component({
  selector: 'app-page',
  templateUrl: './page.component.html',
  styleUrls: ['./page.component.css']
})
export class PageComponent implements OnInit {

  @ViewChild('sider')
  sider;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {
  }

  ngOnInit() {
    
      const componentFactory = this.componentFactoryResolver.resolveComponentFactory(SomeComponent);
 this.sider.viewContainerRef.createComponent(componentFactory);
    });
   
  }

}

and normally will see you component loaded at the place of you ng-template (you can call https://angular.io/api/core/ViewContainerRef#clear if you want to reset your view)

I already play with this, you can find some code here https://github.com/nicearma/dynamic

nicearma
  • 750
  • 2
  • 8
  • 21
0

I thought to leave this here for anyone who encounters the same issue in the future.

If you don't want to bother manually instantiating components with ComponentFactory as the other answers suggest, you can also use a library I wrote for the explicit purpose of loading components into dynamic content: ngx-dynamic-hooks.

You can give it any string that contains the selector of a desired component and it will automatically be loaded in its place. You can even load components by other text patterns other than just their selectors! See it in action in this Stackblitz.

There's a lot more bells and whistles, if you need them. In the link above, you'll find a fairly detailed documentation that should set you up easily.

Mvin
  • 385
  • 4
  • 12