Pass TemplateRef with data to 3rd party library - html

I'm using ng-zorro-antd library and I'm trying to pass a ng-template without duplicating HTML.
The component (in the url) expects TemplateRef as an Input property (nzDot).
This is my ng-template:
<ng-template #dotTemplate let-step>
<div [ngSwitch]="step.status">
<span *ngSwitchCase="'active'" nz-icon nzType="info-circle" nzTheme="outline"></span>
<span
*ngSwitchCase="'error'"
nz-icon
nzType="info-circle"
nzTheme="fill"
class="text-volcano-6"
></span>
<span
*ngSwitchCase="'onboarding'"
nz-icon
nzType="info-circle"
nzTheme="outline"
class="text-yellow-6"
></span>
<span
*ngSwitchCase="'syncing'"
nz-icon
nzType="sync"
nzTheme="outline"
class="text-geekblue-6"
></span>
</div>
</ng-template>
What I'm trying to do is basically send this step object (let-step) as variable to the outlet, but I don't see a way to do this, as this is controlled by the ngTemplateOutlet inside of the 3rd party component.
Is there any smart way to do this?
I see that I can make 4 templates and then bind to the property like this:
step.status === 'Active'
? dotActiveTemplate
: step.status === 'syncing'
? dotSyncingTemplate
: step.status === 'onboarding'
? dotOnboardingTemplate
: dotErrorTemplate
But this solution seems bad and I would appreciate help.
Thanks!

Related

How to change color of a badge programmatically

i would like to know how can i change the color of a badge programmtically in angular.
i would like to be able to set the color of the badge initially to white and if the percVLRiskTotal is equal a specific value, then the color of the badge should be set to green for an example.
css:
<span class="badge badge-purple">{{percVLRiskTotal}} <span class="clr-sr-only"></span></span>
There are multiple ways to set a style class conditionally in Angular. For your case, you could do something like:
<span class="badge" [class.badge-green]="percVLRiskTotal === 1000">
{{percVLRiskTotal}} <span class="clr-sr-only">
</span>
This will apply the class named badge-green to the span element if the value of the percVLRiskTotal property equals 1,000.
More information can be found here.
based on your sample I think u can use ngClass like this:
[ngClass]="{'badge-purple': yourCondition === 'Option'}"
or for multiple conditions:
[ngClass]="{'badge-purple': yourCondition1 === 'Option1', 'badge-red' : yourCondition2 === 'Option2' }"
There are many methods to achieve. This
here I think you can use the ngStyle directive provided by angular
<span class="badge" [ngStyle]="{'background-color': percVLRiskTotal == 50 ? 'green':'blue'}">{{percVLRiskTotal}} <span class="clr-sr-only"></span>

Variabilizing the # from <mat-menu>

I'm currently trying to generate a dynamic menu from a JSON blob in my typescript files, Angular project.
I'm using the / component from Angular Material.
My json menu has this structure :
{
id: 0,
titreTranslate: 'menu-accueil',
isDescriptionRequired: true,
routerLink: '/accueil',
icon: faHome,
isAllowed: true,
hasSubOptions: false,
trigger: 'accueil'
}
My code look something like this :
<mat-toolbar-row class="navigation-row">
<span *ngFor="let option of menuOptions">
<button mat-button
[matMenuTriggerFor]="admin"
routerLink="{{option.routerLink}}"
(keyup.enter)="router.navigate([option.routerLink], { queryParams: option.queryParams })"
[routerLinkActive]="['active-menu']"
[queryParams]="option.queryParams"
class="link bouton-menu-gauche flex-row"
*ngIf="option.isAllowed"
>
<fa-icon
*ngIf="option.icon"
class="primary-color"
[icon]="option.icon"></fa-icon>
{{ option.titreTranslate | translate }}
</button>
<mat-menu #{{option.trigger}}="matMenu">
<span *ngFor="let subOption of option.menuOptions">
<button mat-menu-item
*ngIf="option.menuOptions"
routerLink="{{subOption.routerLink}}"
(keyup.enter)="router.navigate([subOption.routerLink], { queryParams: subOption.queryParams })"
[routerLinkActive]="['active-menu']"
[queryParams]="subOption.queryParams"
class="link bouton-menu-gauche flex-row">
<fa-icon
*ngIf="subOption.icon"
class="primary-color"
[icon]="subOption.icon"></fa-icon>
{{ subOption.titreTranslate | translate }}
</button>
</span>
</mat-menu>
</span>
</mat-toolbar-row>
The line with " <mat-menu #{{option.trigger}}="matMenu"> " is what concerns me here ; I've tried many ways to variabilize this #, such as putting it directly in the Json menu or trying different syntax ; It always fail, and won't give me the code structure i want.
If i had to guess, i'd say the generated code should look like : <mat-menu #"accueil"="matMenu">, with "" that fail to compile ; but i don't get any compilation errors, so i'm lost here.
Does anybody had to work with that kind of structure before ?
(apologies for my english if it's bad, i'm french)
Check out this answer:
https://stackoverflow.com/a/44441164/2025458
It's easier to search for the answer if you call things by the name they are given in the documentation, the '#' is a template reference or template variable
And since it's inside a structural directive (*ngfor or any other directive strating with *)
It binds to a template created by the structural directive, so every loop of the ngfor generates its own nested template with its own instance of the variable, so you can just use one name

How to use "v-if" in Vue.js to render a <span> only if parent div has a specific property?

What I'm trying to do is make it so that <span v-if="spinnerToggle && command-id=='updateAllExternalReferences'">Spin</span> only renders when spinnerToggle has a value of true and the parent div has a command-id property of updateAllExternalReferences.
I've been able to get this to work using only the spinnerToggle conditional, but adding the command-id one causes it to give me the following error:
[Vue warn]: Property or method "id" is not defined on the instance
but referenced during render. Make sure that this property is
reactive, either in the data option, or for class-based components, by
initializing the property.
Does v-if not support conditionals that reference properties in the parent div? If so, how should I implement this sort of functionality? Below you'll find the parent div and the respective <span>.
<div class="tool is-activatable"
v-if="config.isVisibleToUser"
#click="dispatch"
:class="[config.cssClass, {'is-active': active, 'is-highlighted': highlight, 'is-button': !context.reordering}]"
:command-id="config.command"
:context-menu-name="contextMenu.name"
:context-menu-details="contextMenu.contextMenuDetails"
:data-id="config.id"
:disabled="disabled"
:data-placement="inMenu ? 'right-top' : config.tooltipPosition || 'bottom'"
:data-original-title="(config.tooltipKey || config.tooltip || config.toolName) | i18next"
:data-expanded-content="(config.expandedTooltipKey || config.expandedTooltip) | i18next" data-html="true"
:data-expand-delay="inMenu ? 0 : config.expandDelay > -1 ? config.expandDelay : 2000"
:data-trigger="config.tooltipTrigger"
:tooltip-dynamic-snippet-id="dynamicSnippetId">
<img v-if="!hasIcon && config.img" :src="config.img" />
<ToolIcon v-if="hasIcon" :icon="config.icon" :iconUri="config.iconUri" :initials="config.iconInitials"
:awaitingData="false" :updateAvailable="config.isNewerVersionAvailable"/>
<span v-if="spinnerToggle && command-id=='updateAllExternalReferences'">Spin</span>
<span class="tool-label" :class="{'hide-in-toolbar': !shouldShowLabel}">
{{ (config.toolDisplayName || config.toolName) | i18next }}
</span>
<ShortcutKeys v-if="inMenu" :shortcut="shortcut" />
<div v-if="context.reordering" class="drag-handle"></div>
</div>
You can't directly reference the attribute from the parent <div> but you can reference the same data that was used to populate it:
<span v-if="spinnerToggle && config.command === 'updateAllExternalReferences'">Spin</span>
If the command-id expression were more complicated you could refactor to use a computed property rather than duplicating the same logic in both places.

What is the proper way to show different elements based on function return

So basically what I want is to show
'Something1' when the job is not processing
'Something2' when the job is running and status is '0'
'Something3' when the job is running but status is something else
I tried the following code snippet, but it looks like let-status in the outer template will never get assigned. Not sure whether the implementation is correct or not, could anyone give me two cents on how to make this logic work?
Thanks.
<span *ngIf="!isProcessing(); else elseBlock">
Something1
</span>
<ng-template #elseBlock let-status="queryPlaybackStatus()" *ngIf="queryStatus() === '0'; else innerElseBlock">
<span>
Something2
</span>
<ng-template #innerElseBlock>
<span>
Something3
</span>
</ng-template>
</ng-template>
I would suggest defining a string in your component, where you have much better control over your logic. In the component, set the string to the appropriate text.
Then bind to that string in the template.
I don't have all of your needed logic here, but something like this:
isImage = false;
get statusText(): string {
if (!isProcessing()) {
this.isImage = false;
return 'Something1';
} else {
this.isImage = true;
return 'path to image';
}
}
This uses a getter, which provides a way for a component property to have logic.
Then just bind to statusText in the template.
<span *ngIf='!isImage'>
{{statusText}}
</span>
<span *ngIf='isImage>
<img ...>
</span>
<span *ngIf="!isProcessing(); else elseBlock">
Something1
</span>
<ng-container #elseBlock *ngIf="queryStatus() as status">
<span *ngIf="status === '0'; else innerElseBlock">
Something2
</span>
<ng-template #innerElseBlock>
<span>
Something3_with_{{status}}%
</span>
</ng-template>
</ng-container>
So basically this need a magic combination of ng-container and ng-template.
It sounds to me like you want ngSwitch. This allows you to switch based on logic, which you should encapsulate in your component, not your template. First, let's create a property that encapsulates our logic in our component:
public get currentStep(): number {
if (!this.isProcessing) {
return 1;
} else if (this.queryStatus === 0) {
return 2;
} else {
return 3;
}
}
Next, let's bind our ngSwitch statement to this newly-created property:
<div [ngSwitch]="currentStep">
<div *ngSwitchCase="1">
<p>Something1</p>
<div>Put whatever you want in here! Images, etc.</div>
</div>
<div *ngSwitchCase="2">
<p>Something2</p>
<p>Loading....</p>
</div>
<div *ngSwitchCase="3">
<p>Something3</p>
<p>All done!</p>
</div>
</div>
That should get you where you need to go. Since this is simple, I created a stackblitz example that will demonstrate a working version of this. In the example, you can click a button and watch the app cycle through all the steps (I'm using setTimeout to simulate a long-running server query).

Clicking on submenu, in a sidebar, go to a url with Material Design using Angular 4

I am working on a book collection program and I have a static sidebar which will have options and when you click on some of the options it sends you to a url.
I can't get the going to url part to work.
So I just have a sidenav, then a menu item called Store and then a submenu with an item called Amazon.
There may be typos, as I typed this as the code is on a different computer. Basically, how do I get where a submenu will send me to a url? I can do it from the menu item.
<md-sidenav #sidenav mode="side" opened="true" class="app-sidenav">
<md-nav-list>
<button md-list-item>Book Choices</button>
<button md-button>
<span md-list-item
[mdMenuTriggerFor]="amazon">Stores</span></button>
</md-nav-list>
</md-sidenav>
<md-menu #amazon>
<button md-button>
<span md-menu-item>
<span (click)="'http://amazon.com'">Amazon</span>
</span>
</button>
</md-menu>
You cannot navigate to a url using this expression (click)="'http://amazon.com'". You need to use window.location.href or window.open method. Here is how you can do that:
<md-menu #amazon>
<button md-button>
<span md-menu-item>
<span (click)="gotoUrl('http://www.amazon.com')">Amazon</span>
</span>
</button>
</md-menu>
in your typescript code, define the gotoUrl() method:
gotoUrl(url:string){
window.location.href=url;
}
if you want to open the url in a new tab in the browser, then use this code:
gotoUrl(url:string){
window.open(url, "_blank");
}
So while you can use (click) events in angular, if all you need to do is navigate to another url you can always just use good old html and an anchor link. If that's all your looking for keep it simple
<md-menu #amazon>
<button md-button>
<a md-menu-item href="http://amazon.com">
Amazon
</a>
</button>
</md-menu>
If you still want to use a click you can, and the answer below was correct it just had a typo
So add a method in your component like:
goToUrl(url: string) {
window.open(url);
}
And then in your view
<md-menu #amazon>
<button md-button>
<span md-menu-item (click)="goToUrl('http://amazon.com')">
Amazon
</span>
</button>
</md-menu>
this thing (click)="'http://amazon.com'" does nothing at all since you just passed a string.
have you tried (click)="window.open('http://amazon.com', '_blank')"?
or create a function that does the window.open(parameter)
openlink(url: string)
{
window.open(string, "_blank");
}
// HTML attribute
(click)="openlink('http://amazon.com')"