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.
Related
I have layout page as below. Layout is responsible for loading all routs in my project. When we use view1 that will load default condition. same way view2, view3 loads its own condition.
<ng-container [ngSwitch]="routeData?.layout">
<ng-container *ngSwitchCase="'view2'"> Some HTml and <router-outlet></router-outlet></ng-container>
<ng-container *ngSwitchCase="'view3'"> Some HTml and <router-outlet></router-outlet></ng-container>
<ng-container *ngSwitchDefault>Some HTml and <router-outlet></router-outlet></ng-container>
When i have been in the page which using the view1(default layout) and i am trying to navigate the other page which also using the view1. browser URL getting changed but Router-outlet not loading new page.
I have understood that when switch case is executing the same case which is not detecting any changes.
Could you please guys suggest any proper way to update switch case data or any good approach to resolve this issue.
The above issue i have solved using below approach.
<ng-template #temp>
<router-outlet></router-outlet>
</ng-template>
<ng-container [ngSwitch]="routeData?.layout">
<ng-container *ngSwitchCase="'view2'"> Some HTml and <ng-container *templateOutlet="temp"></ng-container></ng-container>
<ng-container *ngSwitchCase="'view3'"> Some HTml and <ng-container *templateOutlet="temp"></ng-container></ng-container>
<ng-container *ngSwitchDefault>Some HTml and <ng-container *templateOutlet="temp"></ng-container></ng-container>
First of all, want to emphasize that I had already have a look at many pages e.g. Two switch case values in angular but they cannot fix my problem.
I have the following approach in the html page of my Angular project and I switch according to i parameter without any problem. On the other hand, there is a parameter called loading on component side and I also need to use this value in ngSwitchCase. But the following code does not work and ignore loading parameter's value. So, how can I use it?
<ng-container [ngSwitch]="i">
<ng-container *ngSwitchCase="i === 0 && loading === true">
<!-- other stuff -->
</ng-container>
</ng-container>
Create another ng-container inside with the loading condition.
<ng-container [ngSwitch]="i">
<ng-container *ngSwitchCase="0">
<ng-container *ngIf="loading">
// do stuff
</ng-container>
</ng-container>
</ng-container>
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
I'm stuck in a situation, in a nested loop. The top loop iterating over the Feeds array and every feed in Feeds have comments array. This comments is used for inner loop.
My problem is, I have Comment button and on click of that button, I want to show the list of comments only for that feed post. But instead of showing comments on current feed post, it is showing comments for all other feeds also, that's because of use of only one Boolean variable showComments created inside .ts file.
So how can make that work for only the given context Feed post?
HTML
<ng-container *ngFor="let feed of feeds">
<div class="ed-card ed-card-feed">
<div class="ed-card-feed--footer">
<div class="card-feed-values">
<a class="mr-4"><span>{{feed.likes_count}}</span> Likes</a>
<a><span>{{feed.comments_count}}</span> Comments</a>
</div>
<div class="card-feed-actions">
<a class="mr-5" (click)="likePost(feed.id)"><span></span> Like</a>
<span></span> Comment button
</div>
</div>
// Below div needs to be open for that particular feed only
<div *ngIf="showComments" class="ed-card-feed--comments">
<div class="feed-comments-list">
<ng-container *ngFor="let comment of feed.comments?.edges">
<div class="comment-list-item">
<p class="comment-box mt-1">
{{comment.node?.body}}
</p>
</div>
</ng-container>
</div>
</div>
</div>
</ng-container>
P.S. - Please don't confuse with feed.comments?.edges that's just because of GraphQL. It is just an array.
Thanx
You can maintain an array of showComments[] equal to size of feeds with initially set to false. showComments[false,false...]
<ng-container *ngFor="let feed of feeds; let myIndex = index"">
//code here
<span></span> Comment button
//check if true
<div *ngIf="showComments[myindex] === true" class="ed-card-feed--comments">
</ng-container>
Instead of a boolean, you can define a selectedFeeds array:
selectedFeeds = new Array<Feed>();
In the template, you add the feed that has been clicked to selectedFeeds:
<a href="javascript:void(0)" class="mr-5" (click)="selectedFeeds.push(feed)>Comment button</a>
and you filter the comments according to the selected feeds:
<div *ngIf="selectedFeeds.indexOf(feed) >= 0" class="ed-card-feed--comments">
The best way to achieve this is to separate the code to different components. And since each of the component will have it's own instance of comments - you won't have a problem creating a local variable and showing/displaying the comments in there.
I've created an example of how it can be implemented: stackblitz
Another approach
<ng-container *ngFor="let feed of feeds">
Comment button
<div *ngIf="feed.showComments" class="ed-card-feed--comments">
</ng-container>
Js file
toggleComments(feed) {
feed.showComments = true // (feed.showComments = !feed.showComments => to show or hide (toggle))
}
I have this html code
<empty-list [hidden]="!emptylist" text="There is currently No User"</empty-list>
<div *ngFor="let userObser of userObservables">
<ion-item #emptylist *ngIf="userObser | async as user">
<h2>{{user.displayName}}</h2>
<h3>{{user.email}}</h3>
</ion-item>
</div>
I want to show the empty list if there is no user & hide it if there is at least one.
I know I can do it using a subscribe method,but I want to use async pipe also I need to unsubscribe each time I use a subscribe which is really not efficient.
My question is there a way I could create a local variable inside the ion-item the ntest test if it exists outside & therefore use it in the hidden input ? It's just a suggestion I can't really seem to make it work.
You can use a simple else inside the ngIf to display another template if the condition doesn't match:
<ng-container *ngIf="userObservables.length > 0; else emptyList">
<ng-container *ngFor="let user of userObservables">
<ion-item *ngIf="user | async as user">…</ion-item>
</ng-container>
</ng-container>
<ng-template #emptyList>
<empty-list>…</empty-list>
</ng-template>
Note that I also replaced your seemingly unnecessary div with a ng-container to avoid unnecessary DOM nodes.
As a side note to your own suggestion: template references cannot be accessed from outside the template boundary. Structural directives like *ngIf and *ngFor create their own template, so this becomes a boundary. That's why
<h2>{{ ref.innerText }}</h2>
<ng-container>
<span #ref>Hello, World</span>
</ng-container>
will work, but
<h2>{{ ref.innerText }}</h2>
<ng-container *ngIf="true">
<span #ref>Hello, World</span>
</ng-container>
won't work.