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.
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>
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
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.
Related
I am using an Angular Wrapper for JSON Editor like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
{{act.test_step_id}}
<json-editor [options]="editorOptions" [(data)]="act.action_json" [(eventParams)]="act.test_step_id" (jsonChange)="changeStepActions($event)"></json-editor>
<button mat-raised-button class="w-100-p mt-24" color="primary" (click)="editRecordJson(act.test_step_id)">
<span>Update</span>
</button>
</div>
The problem is that eventParams should be different for each editor but it is not varying.
I think problem is this component code (but not sure) (This line is in the component taken from github):
#ViewChild('jsonEditorContainer', { static: true }) jsonEditorContainer: ElementRef;
The component is behaving like a singleton. Any help?
Edit: I edited this repo and added jsonchange event. Details here
You may want to use #ViewChildren with a direct reference to the component instead of a template variable string, to get all the JSON editors references:
#ViewChildren(JsonEditorComponent) jsonEditorContainers: QueryList<ElementRef>;
// ...
jsonEditorContainers.find(...);
It returns a QueryList that allows you to iterate through all ElementRef, and monitor the changes with an Observable changes.
What is eventParams? What is jsonChange? I could be wrong, but data doesn't seem to be two way bindable either, according to the source code.
It seems like you might be looking for something like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
<json-editor [options]="editorOptions"
[data]="act.action_json"
(change)="changeStepActions($event, act.test_step_id)">
</json-editor>
</div>
You can then read the test_step_id in your changeStepActions method. If this works, I don't know how you made it compile in the first place.. are you using a CUSTOM_ELEMENTS_SCHEMA?
Its not necessary to use #ViewChildren for that you have to rewrite the entire code of component, make sure while using #ViewChild you pass correct editor reference.
As following
#ViewChild('carEditor' ) carEditor: JsonEditorComponent;
#ViewChild('mobileEditor') mobileEditor: JsonEditorComponent;
Stackblitz example for refernce :
Click here for code example
To use multiple jsoneditors in your view you cannot use the same editor options.
You should have something like:
<div *ngFor="let prd of data.products" class="w-100-p p-24" >
<json-editor [options]="makeOptions()" [data]="prd" (change)="showJson($event)"></json-editor>
</div>
makeOptions = () => {
return new JsonEditorOptions();
}
I want to render incoming text from an API as subsequent HTML and component template.
Most of the solutions I found here use #ViewChild to inject the components but that doesn't work for me since I need to iterate the same behavior for all items in the *ngFor loop.
This is how the code would look like:
The template of the component rendering the incoming messages:
<div *ngFor="let item of messages">
<compile-component [template]="item.html"></compile-component>
</div>
Incoming message structure (item.html):
<my-component></my-component><div>Some html</div>
Component to compile:
#Component({
selector: 'my-component',
template: '<div>It works</div>',
styleUrls: ['./my-component.component.css']
})
export class MyComponent{ }
Output would look like this:
<div>It works</div><div>Some html</div>
I am looking for the solution for compile-component here.
Any help is much appreciated. Thanks in advance.
You should be able to do that via ComponentFactoryResolver. See angular docs about this here:
https://angular.io/guide/dynamic-component-loader
What I want to do
I want to create a reusable Angular 2 button component that may render as an <a /> tag or an <input /> tag depending on an input to the component called type. I want the button component to accept content children which will be rendered as the button label.
To illustrate: an Angular template that invokes my button component like so:<button>Hello</button> should render as <a>Hello</a> in the DOM. However, if a property type="submit" is set (e.g. <button type="submit>Hello</button>) then the output in the DOM should be <input type="submit">Hello</input>.
To further clarify, if I were using React I could create [an overly simplified version of] this component with:
const Button = ({ type, children }) =>
type === "submit"
? <input type="submit">{children}</input>
: <a>{children}</a>
Where I'm stuck
Creating an Angular component that displays content children using <ng-content /> was relatively straightforward. However, I'm yet unable to render those children inside a dynamically chosen tag - either <a /> or <input /> depending on the value of the type property.
What I've tried
I initially tried to use <ng-content /> inside an ngIf or ngSwitch directive, only to find out that <ng-content /> can appear at most once in any given template (unless it’s qualified with a selector). However, I want to output all content children so selectors are not helpful.
I keep finding references to DynamicComponentLoader, but that appears to be deprecated.
I've seen the ContentChildren decorator which would allow my button component to access the content children being passed to it, but I'm not sure how to then take those children and inject them into my component template.
I came across NgTemplateOutlet, which seems like it might help me switch between two entirely different templates (one w/ the <a /> tag and one with the <input /> tag). However that's marked as “Experimental” and I’m having trouble understanding the usage.
Any help would be greatly appreciated!!
#Component({
selector: 'adapting-button',
template: `
<a *ngIf="type !== "submit">{{value}}</a>
<input *ngIf="type === "submit" type="submit" [value]="value">
`,
})
export class AdaptingButtonComponent {
#Input() type: any;
#Input() value: any;
}
#Component({
selector: 'app-root',
templateUrl: `
<adapting-button [type]="'submit'" [value]="Hello"></adapting-button>
`,
})
export class AppComponent {
title = 'app works!';
}
All arranged, everything was fine until it became necessary to create a component which is TR.And when inserting that component onto the page Angular2 does the following:
<my-component>
<tr>...</tr>
</my-component>
It all falls down and bleeds. How can I make it not do that? Where to look? Thanks in advance.
In fact there is no more support for the "replace: true" feature of Angular1.
You could leverage an attribute in the selector to attach the component:
#Component({
selector: '[my-component]'
(...)
})
and use it this way:
<div my-component>
<tr>...</tr>
</div>
I'm stuck on a template/component problem and I couldn't find any answer.
I'm trying to move a plain Javascript project to Angular2. In my project, I actually create some elements by inherit from others.
Example:
File header.html
<header class="some_class"></header>
File header_base.html inherits from header.html
<header> <!-- This is the header element from the header.html file. -->
<img class="some_class" src="path/to/my/image">
...
</header>
EDIT:
To clarify how I actually do, to 'inherits file from another', I use Javascript.
My problem is that I can't find out how to do that in Angular.
My question is, is there any way to accomplish something like that or do I need to change my way of 'templating' things ?
Thanks by advance.
Your question is a little confusing. Can you provide more detail about what the end result should be?
It sounds like what you are looking for is shadow dom insertion point where you have a component that you can put content into. Where you have a component called Header that has some markup and styles applied, but then you can use it in different places with different content?
If so, here is how you would do it (Note: this is Typescript but could be done in plain Javascript. Check the Angular docs for examples):
CustomHeader.ts:
#Component({
selector: 'custom-header',
template: '<header class="some-class"><ng-content></ng-content></header>'
})
export class CustomHeader {
//if you need any logic in that component
}
Then in whatever component you need to use this component, you would import it:
app.ts:
import {CustomHeader} from './CustomHeader';
#Component({
selector: "my-app",
directives: [CustomHeader],
template: `<div>
<custom-header>
<img class="some_class" src="path/to/my/image" />
</custom-header>
</div>`
})
The result is that when you use the component in your html, its content will get wrapped by the contents of the CustomHeader's template. Not sure if that is exactly what your need was though.
EDIT: Here's a good article describing this type of component: http://blog.thoughtram.io/angular/2015/03/27/building-a-zippy-component-in-angular-2.html