Angular 4 & PrimeNg: how to add and remove/hide tab-panels - html

I have a tabView and a list of tab-panels.
Based on runtime conditions, I need to hide and unhide one of the tab panels.
Can not find a way to do this using looking at their docs or here.
Any suggestions?
In general is there a way to dynamically add and remove tab panels?
Code I am using now that is not working, my test syntax must be wrong:
<div [ngSwitch]="isNEC">
<ng-template ngSwitchCase="'true'">
<p-tabView>
<p-tabPanel header="Detail">
<linechart #linechart></linechart>
</p-tabPanel>
<p-tabPanel header="Assessment">
Coming soon to a theater near you !!!!
</p-tabPanel>
</p-tabView>
</ng-template>
<ng-template ngSwitchCase="'false'">
<p-tabView>
<p-tabPanel header="Detail">
<linechart #linechart></linechart>
</p-tabPanel>
</p-tabView>
</ng-template>
</div>
unless I put a switch default, nothing ever shows up.
isNEC is a component public attribute of type string

all is well, I just needed to check for 'true' and not "'true'"

Related

prime ng sidebar component header content not showing

Trying to add header in prime ng sidebar component but its not working
<p-sidebar [(visible)]="visibleSidebar1">
 
<ng-template p-Template="header">
<p>"Header"</p>
</ng-template>
My content goes here
</p-sidebar>
Try using pTemplate="header" instead of p-Template="header"
in shared component i tried this and seems to be working
{{Header}}
<p-sidebar [(visible)]="visibleSidebar1"><app-shared-component></app-shared-component></p-sidebar>

Primeng Context menu not working on tabpanel

I have below code
<p-tabView #tabview *ngIf="mycondtion" class="page" [scrollable]="scrollable">
<ng-container *ngFor="let list of lists">
<p-contextMenu [target]="link" [model]="items"> </p-contextMenu>
<p-tabPanel [header]="list.listName" #link>
<app-data-module [List]="list"></app-data-module>
</p-tabPanel>
</ng-container>
on rightclick of tabpanel, it should show the context menu, but its not showing, i dont know what am i missing here? please help
You might be able to use header template (instead of a "header="). Something like this:
<p-tabView #tabview *ngIf="mycondtion" class="page" [scrollable]="scrollable">
<p-tabPanel *ngFor="let list of lists">
<ng-template pTemplate="header">
<!-- Here is where all the header content will go, including the context menu -->
<div #link>{{list.name}}</div>
<p-contextMenu [target]="link" [model]="items"</p-contextMenu>
</ng-template>
<!-- Here is where the content of the tab will go -->
<app-data-module [List]="list"></app-data-module>
</p-tabPanel>
</p-tabView>
The main flaw here is, the context menu only appears when right-clicking on the <div>; clicking anywhere else in the tab header still won't work. I've not found a way around that, but hopefully this will help get you in the right direction.

Setting class for all Angular templates renderable with *ngIf

I have a class section on a DIV to be rendered. It works as expected.
<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates>
<div class="section">...</div>
</ng-template>
I tried moving the class assignment to the DIV containing the directive. The rendition did not work, though.
<div *ngIf="decoded; then coordinates" class="section"></div>
<ng-template #coordinates>
<div>...</div>
</ng-template>
The outer DIV vanishes as a whole, being replaced by the contents of the template. It bugs me because I'm forced to add an extra DIV around everything in my template if I have several components in it. (Also, it seems kind of weird to me that we don't retain any properties of the tag used with *ngIf and can use any arbitrary one, while it seems to work for *ngFor.)
<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates>
<div class="section">
<div>...</div>
<span>...</span>
<bzz>...</bzz>
</div>
</ng-template>
I tried cheating the browser by setting the class on template but since it's not actually rendered in the DOM as such, it failed, of course.
<div *ngIf="decoded; then coordinates"></div>
<ng-template #coordinates class="section">
<div...</div>
</ng-template>
is there a way to force the DIV with the conditional directive to retain its class when being rendered according to the template's contents?
You can try to use ng-container and apply *ngIf to it, in this case it should work as you expected
<div class="section">
<ng-container *ngIf="decoded; then coordinates"></ng-container>
</div>
<ng-template #coordinates>
<div>...</div>
</ng-template>
TL;DR: Angular is doing what you asked it to; you used then to tell it to render something other than the element the directive was on in the truth-y case. If that's not the behaviour you want, don't do that.
Structural directives like *ngIf and *ngFor are really a shorthand that gets expanded (this used to be referred to as "desugaring"), look at the examples in https://angular.io/guide/structural-directives or more specifically https://angular.io/api/common/NgIf#description:
Simple form with shorthand syntax:
<div *ngIf="condition">Content to render when condition is true.</div>
Simple form with expanded syntax:
<ng-template [ngIf]="condition">
<div>Content to render when condition is true.</div>
</ng-template>
Note that everything gets wrapped up in ng-templates for conditional rendering.
If you had written your template like this:
<div *ngIf="decoded" class="section">...</div>
it would get expanded to:
<ng-template [ngIf]="decoded">
<div class="section">...</div>
</ng-template>
and what would actually be rendered is:
<div class="section">...</div>
Note that the class is still included, consistent with what you've experienced in other structural directives.
However, when you use then, the shorthand:
<div *ngIf="decoded; then coordinates" class="section"></div>
<ng-template #coordinates>
<div>...</div>
</ng-template>
is expanded to:
<ng-template [ngIf]="decoded" [ngIfThen]="coordinates">
<div class="section"></div>
</ng-template>
<ng-template #coordinates>
<div>...</div>
</ng-template>
The content of the first ng-template is now irrelevant, because that's not what's rendered in either case. It's either going to render the #coordinates template content or nothing, so you get:
<div>...</div>
and your class seems to have disappeared. But that's what you asked for; the point of then is to not render the element the *ngIf was on, in the truth-y case, but to render something else instead.
For more on these underlying ng- elements, I wrote Angular's "ng-" elements on my blog.
I suggest to take a look on this great article Everything you need to know about ng-template, ng-content, ng-container, and *ngTemplateOutlet in Angula
It contains all you need to know about Angular's structural directives with a good explanation and examples.

Why ngb-tabset resets to first tab when display is hidden and shown?

I use ngb-tabset in a component which is under a single div section. This div tag is displayed based on a condition to be true. When the condition is false, a different section is displayed.
<div *ngIf="showAllTabs">
<ngb-tabset>
<ngb-tab id="heading-1">
<ng-template ngbTabTitle>
<div>HEADING 1</div>
</ng-template>
</ngb-tab>
<ngb-tab id="heading-2">
<ng-template ngbTabTitle>
<div>HEADING 2</div>
</ng-template>
</ngb-tab>
</ngb-tabset>
</div>
<div *ngIf="!showAllTabs">
<!-- Some other work -->
</div>
The issue is, if for instance,the active tab is "heading-2", and when the division tag is hidden and shown again, the active tab is set to the first tab (heading-1) automatically. How to not allow this?
The reason was because of the structural directive "ngIf". ngIf removes the elements from the DOM and so, when the ngIf turns out to be true, the elements are rendered newly which causes the default tab to be made visible. This can be solved by programming the tab selection by storing the id of the tab in a variable and enabling it each time the DOM elements are rendered back.

How do I nest multiple ng-if properly?

I am facing an issue with multiple nested ngIf applied on ng-template elements in Angular.js, and I can't seem to get the perfect answer. I know workarounds but they are not optimized.
This is the code that I am trying to get running:
<div class="container">
<ng-template *ngIf="booleanA;then caseA else caseB">
<ng-template #caseA>
<el>1</el>
<el>2</el>
</ng-template>
<ng-template #caseB>
<ng-template *ngIf="booleanB">
<el>3</el>
<el>4</el>
<el>5</el>
</ng-template>
</ng-template>
</ng-template>
</div>
And these are the two solutions I have found to my problem:
Placing the ngIf on every child element inside of the #caseB element:
<ng-template #caseB>
<el *ngIf="booleanB">3</el>
<el *ngIf="booleanB">4</el>
<el *ngIf="booleanB">5</el>
</ng-template>
Placing the surrounding class="container" element inside both #caseA and #caseB, and applying the second ngIf to it:
<ng-template *ngIf="booleanA;then caseA else caseB">
<ng-template #caseA>
<div class="container">
<el>1</el>
<el>2</el>
</div>
</ng-template>
<ng-template #caseB>
<div *ngIf="booleanB" class="container">
<el>3</el>
<el>4</el>
<el>5</el>
</div>
</ng-template>
</ng-template>
The issue with these solutions is in the optimization. The first one checks multiple times for the same value, and the second one uses the same HTML element twice.
Is there any way I could make the original design work?
EDIT: The two solutions wouldn't appear as blocks of code, therefore I styled them as inline code. If you know how to fix that you'd be very welcome.
EDIT 2: Bringing some clarification as to what I am looking for: The end goal is not for the code to work, I have already found workarounds that I could use if all else fails.
The end goal is to get this code working only with Angular's logical element <ng-template> and by following the original design; and without the help of additional native elements like div, which would alter the DOM.
Two changes you need to make
Using ng-container
Using div instead of nested ng-template
please see this stackblitz
<div class="container">
<ng-container *ngIf="booleanA; then caseA; else caseB">
</ng-container>
<ng-template #caseA>
<span>1</span>
<span>2</span>
</ng-template>
<ng-template #caseB>
<div *ngIf="booleanB">
<span>3</span>
<span>4</span>
<span>5</span>
</div>
</ng-template>
</div>
You can try to use ngSwitch:
https://angular.io/api/common/NgSwitch
example code from Angular:
<container-element [ngSwitch]="switch_expression">
<some-element *ngSwitchCase="match_expression_1">...</some-element>
<some-element *ngSwitchCase="match_expression_2">...</some-element>
<some-other-element *ngSwitchCase="match_expression_3">...</some-other-element>
<ng-container *ngSwitchCase="match_expression_3">
<!-- use a ng-container to group multiple root nodes -->
<inner-element></inner-element>
<inner-other-element></inner-other-element>
</ng-container>
<some-element *ngSwitchDefault>...</some-element>
</container-element>
I have found a way to keep the mindset of my original design without adding unnecessary new DOM elements, duplicating HTML code, or double-checking the same variable.
<div class="container">
<ng-template *ngIf="booleanA;then caseA else caseB">
<ng-template #caseA>
<el>1</el>
<el>2</el>
</ng-template>
<ng-template #caseB>
<ng-template *ngIf="booleanB;then caseC"></ng-template>
<ng-template #caseC>
<el>3</el>
<el>4</el>
<el>5</el>
</ng-template>
</ng-template>
</ng-template>
</div>
Thanks to everyone for giving me other paths to explore, those will serve me well.