I am using primeng TurboTable where for templates a pTemplate directive is added. And then accordingly DOM gets rendered I am trying to implement a very same approach in my project to create a reusable(DUMB) component. Tried searching for a solution but couldn't find a proper solution. Thought about using ng-container but when passing ng-template from Smart component to child component nothing is happening. PFB a sample of the solution I tried
Smart Component Template
<dumb-component>
<ng-template #content> Content is placed here .... </ng-template>
</dumb-component>
Dumb Component Template
<ng-container *ngTemplateOutlet="content">
</ng-container>
Link to primeng documentation : primeng docs
Since your component Dumb Component receives a template. It needs to access the template with #ContentChild
Dump Component
<ng-container *ngTemplateOutlet="content">
</ng-container>
#ContentChild(TemplateRef) content: TemplateRef<any>;
Example:https://stackblitz.com/edit/angular-ephusu
Related
In a context of a micro-front-end application I have a projected content in the app.module.ts that I want to put in a component that was instantiated via the router.
Here is a solution that does not work:
I referenced the projected content as follow
<ng-template #projected>
<ng-content></ng-content>
</ng-template>
<router-outlet></router-outlet>
I set the reference in a service
#ViewChild('projected', { static: true }) templateRef: TemplateRef<unknown>;
// ...
this.service.projectedRef = templateRef;
use it in the component that was created by the router
<ng-container [ngTemplateOutlet]="service.projectedRef"></ng-container>
Any idea why doesn't that work and how I can solve this problem?
Note: when I use <ng-container [ngTemplateOutlet]="service.projectedRef"></ng-container> inside the app.component.html, it works fine, but not inside the routed component.
I have a list of child components inside a ngFor:
<ng-container *ngFor="let field of fields">
<button (click)="show = !show">Show</button>
<ng-container *ngIf="show">
<app-field [fieldInfo]="field"></app-field>
</ng-container>
</ng-container>
I want to only show this specific app-field component if show is true, but this is obviously not the way, because it sets show to true for all of the rendered components.
My problem is really that I cant show all of the app-fields because they turn my app into a slow mess when they are displayed (there will be hundreds of them), so I only want to display them when they are needed.
How can I toggle the rendering of each specific component on/off uppon click? Or is there som other solution I could look into?
show variable is global and updating value for show will reflect for all the app-field components, Thus You need to determine and specify a show/hide variable for each component individually.
To do that you should add a show member inside the field Object as follow:
<ng-container *ngFor="let field of fields">
<button (click)="field.show = !field.show">Show</button>
<ng-container *ngIf="field.show">
<app-field [fieldInfo]="field"></app-field>
</ng-container>
</ng-container>
Also found similar solution, check this answer
I needed to only have the component be attached to the DOM when set to be visible. Solved it with the answer in: Thierry Templier answer here
Inside parent component:
public showField: any = {};
Then in parent component template:
<ng-container *ngFor="let field of fields">
<button (click)="showField[childField.id] = !showField[childField.id]">Show</button>
<ng-container *ngIf="showField[childField.id]">
<app-field [fieldInfo]="field"></app-field>
</ng-container>
</ng-container>
This destroys the component when *ngIf is false, which is what I needed in this situation.
Thanks to #yazan for leading me to the answer.
I have two angular components whose respective templates are called home.component.html and information-icon.html.
I am using custom HTML elements, so when I define my custom elements together only in one template, for example in home.component.html, the template shows correctly elements defined:
<!-- home.component.html-->
<sh-access-bar label="Access bar">
<sh-button icon="example.png"></sh-button>
</sh-access-bar>
Nevertheless, I need two separate components to my purpose, so If I defined both templates like this, the component doesn't render correctly:
First component:
<!-- home.component.html-->
<sh-access-bar label="Access bar">
<app-information-icon></app-information-icon> <!--Component selector-->
</sh-access-bar>
Second component:
<!--information-icon.component.html-->
<sh-button icon="example.png"></sh-button>
Are there any way in Angular to render both components correctly?
Are there any properly way to create custom tags dynamically as a component?
I will appreciate any kind of help.
I'm trying to clone the ng-content items of a component along with any functionality added on the HTML of that content. For example, the markup using the component might look like this:
<custom-component>
<button (click)="doAThing();">A button</button>
</custom-component>
Then I set up my template for custom-component like so:
<ng-template #content>
<ng-conent></ng-content>
</ng-template>
<ng-template *ngTemplateOutlet="content"></ng-template>
<div class="second-area>
<ng-template *ngTemplateOutlet="content"></ng-template>
</div>
My expectation would be that the ng-content would get duplicated into both ngTemplateOutlet areas. What happens is that it pushes to the last outlet and ignores the first. This markup will duplicate normal markup just fine, but ng-content only move to one outlet.
Is this not possible with this technique, am I missing something obvious, or it there another way to clone the contents of ng-content along with any events attached to it?
I found this solution that worked for me. First the HTML, you'll need a directive to wrap the content in so you can reference it. You'll need to use asterisk with directive so it can be duplicated.
<custom-component>
<ng-container *customDirective>
<button (click)="doAThing();">A button</button>
</ng-container>
</custom-component>
The directive doesn't require any extra code. We just need it for a reference.
In your custom-component, you'll need to create a reference to the diretive via #ContentChild like so:
#ContentChild(CustomDirective, { read: TemplateRef }) transcludeTemplate;
Then we use the following for our custom-component HTML avoiding using ng-content tags all together:
<ng-template *ngTemplateOutlet="transcludeTemplate"></ng-template>
<div class="second-area>
<ng-template *ngTemplateOutlet="transcludeTemplate"></ng-template>
</div>
So this isn't really the same as duplicating <ng-content>, but it gives us a similar function. Apparently ng-content not multiplying is intended behavior. So this might be the best way to achieve a similar goal.
I am facing the problem, that I need to pass multiple ng-template into another component as a template, example:
<app-datatable>
<ng-template tdDataTableTemplate="description" let-value="value" let-row="row" let-column="column">
<p matTooltip="{{ row[column ]}}">{{ row[column] }}</p>
</ng-template>
<ng-template tdDataTableTemplate="vendorName" let-value="value">
<p matTooltip="{{ value }}">{{ value }}</p>
</ng-template>
</app-datatable>
app-datatable is my component and I need to pass these templates to it as a template.
td-data-table is Teradata covalent DataTable component. It has functionality, that I can template each column with ng-template. But I want to pass ng-template through my component into td-data-table - hope it makes sence
Solution:
I didn't manage to find Covalent way solution. But I've managed to rewrite Teradata grid to custom grid, which allows me more control over it. Here is Stackblitz: Demo
I encountered the same problem and managed to fix it with the following:
In datatable.component.ts:
#Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.scss']
})
export class DataTableComponent implements OnChanges, AfterContentInit {
ngAfterContentInit(): void {
for (let template of this.templates.toArray()) {
if (!template.tdDataTableTemplate) {
continue
}
this.tdDataTable._templateMap.set(template.tdDataTableTemplate, template.templateRef)
}
}
#ViewChild(TdDataTableComponent) tdDataTable;
#ContentChildren(TdDataTableTemplateDirective) templates;
}
This mimics how TdDataTableCompponent handles the templates under the hood.
Also, for completeness, I spoke to the OP on the covalent gitter and they said that they solved it by rewriting the data table from the individual covalent components. They shared a stackblitz here.