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.

9
  • 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. Commented Jan 12, 2018 at 4:59
  • @Devcon Thanks for the answer, can you give me any example of this? Commented Jan 12, 2018 at 6:04
  • @Justcode This ain't yo'mama´s AngularJS ;D Joking aside, you cannot add new components like in AngularJS watch and weep youtube.com/… Commented Jan 12, 2018 at 11:28
  • @user1740331 I was able to do this easily before in 1.0 :P any ways thanks for the link. Commented Jan 12, 2018 at 15:42
  • 1
    you can do it with angular.io/guide/dynamic-component-loader Commented Jan 14, 2018 at 22:23

3 Answers 3

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>

Sign up to request clarification or add additional context in comments.

3 Comments

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
i finally found it cannot be done with input elements as Angular sanitize almost all elements except block level and inline elements.
@worstCoder that's great. its recommended to keep the html in html file. it will be always helpful.
5
+25

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

3 Comments

Thanks for your answer, the viewchild is dynamic itself. whole view is being created dynamically runtime. So, I resolved it using the ng-template directive. I will post answer today.
@Just code: how did you load the dynamic html into div of component?
@user2439903 by resolving the factory instance?
1

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.

1 Comment

Indeed, this library makes it so easy! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.