Using $implict to pass multiple parameters - html

I have a template to be recursive, something similar to below:
<ng-container *ngTemplateOutlet="testTemplate; context: {$implicit:jsonObj1}">
</ng-container>
<ng-template #testTemplate let-Json1>
</ng-template>
It works fine, I send jsonObj1 using $implicit, but I would like to send two parameters to , if I try:
context: {$implicit:jsonObj1, $implicit:jsonObj2}
and try to access using
<ng-template #filterTemplate let-Json1 let-json2>
</ng-template>
It doesn't work, let me know, how to pass two parameters.

You don't need to use $implicit
You can use
1:
context: {$implicit:jsonObj1, b:jsonObj2}
with
<ng-template #filterTemplate let-json1 let-json2="b">
<div>{{json1}}</div></div>{{json2}}</div>
</ng-template>
or 2:
context: {$implicit: {a: jsonObj1, b:jsonObj2}}
with
<ng-template #filterTemplate let-json1>
<div>{{json1.a}}</div></div>{{json1.b}}</div>
</ng-template>
or 3:
context: {a:jsonObj1, b:jsonObj2}
with
<ng-template #filterTemplate let-json1="a" let-json2="b">
<div>{{json1}}</div></div>{{json2}}</div>
</ng-template>

Here are couple more (similar) options, this one includes using 'ngTemplateOutletContext' and also a condition (in 4th argument - for fun).
... to try - should work by copy and paste ...
<!-- DEMO using:
"=templateID; context:{prop:value, ...}"
( 4 arguments demo)
Note: $implicit identifies the default argument in the template.
The template does not need to assign the argument name,
- see the 3rd argument
-->
<div *ngFor="let item of ['Aaa', 'Bbb', 'Ccc']; index as ix">
<ng-container *ngTemplateOutlet="myTemplate1;
context:{cDemoName:'Option 1:',
cIx:ix+1,
$implicit:item,
cIsEven: ((ix % 2) === 0) ? 'true' : 'false' }">
</ng-container>
</div>
<hr>
<!-- DEMO using:
[ngTemplateOutlet]="templateID"
[ngTemplateOutletContext]="{"=templateID; context:{prop:value, ...}"
-->
<div *ngFor="let item of ['Dddd', 'Eee', 'Fff']; index as ix">
<ng-container [ngTemplateOutlet]="myTemplate1"
[ngTemplateOutletContext]="{
cDemoName:'Option 2',
cIx:ix+1,
$implicit:item,
cIsEven: ((ix % 2) === 0) ? 'true' : 'false' }
">
</ng-container>
</div>
<!-- DEMO template:
( 4 arguments expected)
-->
<ng-template #myTemplate1
let-cDemoName="cDemoName"
let-cIx="cIx"
let-cItem
let-cIsEven="cIsEven">
Context arguments demo name: {{cDemoName}} <br>
. . . . . Context index: {{cIx}} <br>
. . . . . Context item: --- {{ cItem }} --- <br>
. . . . . Context is-even: {{ cIsEven }} <br>
<br>
</ng-template>

Related

why there is extra comment tag in the final DOM generate by angualr

bindings={
“ng-reflect-ng-if”: “false”
}
<ng-template class=“no-result-product” [ngIf]=“products” [ngIfElse]=“noproducts”>
<div class=“list-product” fxLayout=“row wrap” fxLayoutAlign=“center stretch” *ngIf=“products”>
<app-template-product *ngFor=“let product of products”
class=“list-product__item”
[product]=“product”>
</app-template-product>
</div>
</ng-template>
<ng-template #noproducts>
<div> <img src=“./assets/img/shop/not-found-product.svg” alt=“”>
<div >{{ ‘not.found.product.message’ | translate }}</div>
</div>
</ng-template>
{{ ‘not.found.product.message’ | translate }}
the content is not displayed !!
here you are using ngIf directive, and passing your 2nd template inside of ngIfElse property
<ng-template class=“no-result-product” [ngIf]=“products” [ngIfElse]=“noproducts”>
that means that your "else template" will appear if products value is falsy.

ng select - multiple values - select same values more than once

is there a way to use ng select to have multiple selections and the possibility to have the same value/s more than once in the same selection?
I could only achieve multiple with each value possible to choose only once:
HTML code:
<ng-select [closeOnSelect]="false" [selectableGroup]="true" [items]="allowedValues"
[(ngModel)]="selectedValuesArray" [selectableGroupAsModel]="false"
(change)="raiseChangeEvent($event)" name="dropdown-element" [multiple]="true" [maxSelectedItems]="maxLength"
[clearable]="false">
<ng-template ng-option-tmp let-item="item">
<div class="option-line">
<p>{{item == null ? 'N/A' : item}}</p>
</div>
</ng-template>
</ng-select>
You could exploit the bindLabel and bindValue attributes.
suppose you pass in the following items:
allowedValues= [
{label: 1, value: 'first_0'},
{label: 2, value: 'second_0'}
]
Your HTML will look like this, mind the addition of bindLabel and bindValue, the change in (change) and the [hideSelected] attribute:
<ng-select [closeOnSelect]="false" [selectableGroup]="true" [items]="allowedValues"
[(ngModel)]="selectedValuesArray" [selectableGroupAsModel]="false"
(change)="raiseChangeEvent($event); addItem($event)" name="dropdown-element" [multiple]="true" [maxSelectedItems]="maxLength"
[clearable]="false" bindLabel="label" bindValue="value" [hideSelected]="true">
<ng-template ng-option-tmp let-item="item">
<div class="option-line">
<p>{{item == null ? 'N/A' : item}}</p>
</div>
</ng-template>
</ng-select>
Whenever an item is selected you could insert a new one in the list with the addItem() function. For example when the user selects 1, add {label: 1, value: 'first_1'} to the allowedValues. This way you will end up with an array of values that are unique, but the user is tricked into believing he is actually clicking the same items over and over again.

Get data from nested json in Angular

Im trying to iterate over an array but page is displaying [ object Object] instead. How can I get data.id of my example?
Service:
return this._http.get<CustomersList[]>(this.apiUrl,{ headers: reqHeader });
My json looks like this:
[ {"current_page":1,"data":[{"id":25},{"id":26}] }]
And here is my component:
customerslist$: CustomersList[];
return this.customerdataService.getCustomersList().subscribe(data => this.customerslist$ = data);
Would be great if anybody can help me?
The data property is an array contained in an array. You either need two *ngFor directives
<ng-container *ngFor="let customer of customerslist$">
<ng-container *ngFor="let item of customer.data">
{{ item.id }}
</ng-container>
/ng-container>
Or if you're sure the customerslist$ array will always contain only one element, you could access the first element directly.
<ng-container *ngFor="let item of customerslist$[0].data">
{{ item.id }}
</ng-container>
Also if you're aren't using the this.customerList$ in the controller, you could skip the subscription in the controller and use the async pipe in the template. It takes care of any potential memory leak issues due to open subscriptions.
Contoller
customerslist$: Observable<CustomersList[]>; // <-- typeof `Observable`
ngOnInit() {
this.customerslist$ = this.customerdataService.getCustomersList(); // <-- don't subscribe yet
}
<ng-container *ngIf="(customerslist$ | async) as customerslist">
<ng-container *ngFor="let customer of customerslist">
<ng-container *ngFor="let item of customer.data">
{{ item.id }}
</ng-container>
</ng-container>
</ng-container>
By convention, variable names suffixed with a dollar sign (customerlist$) are used to denote observables.
If you are using Observable $ sign at the end of variable denotes observable,
in that case you do not need to subscribe only return value, in template you can subscribe using async pipe which automatically unsubscribe as well to prevent memory leak and a recommended approach.
Here we assume we are only taking first element of array that why directly accessing it giving first index, otherwise we need to iterate that array in template as well.
customerslist$: Observable<CustomersList[]>;
this.customerslist$ = this.customerdataService.getCustomersList()
.pipe(map(res) => res[0].data));
In template use async pipe to subscribe
<ng-container *ngFor="let data of customerslist$ | async">
<span> {{ data.id }} </span>
</ng-container>
WITHOUT OBSERVABLE
customerslist: CustomersList[];
this.customerdataService.getCustomersList()
.subscribe((res) => this.customerslist = res[0].data));
In template
<ng-container *ngFor="let data of customerslist">
<span> {{ data.id }} </span>
</ng-container>

Display row only if certain conditions are met

I'm a intern, and I need some help.
I've a ngx-datatable, and I want to display row when condition are met. How can I do it? For example, if country covered is America, I display, if not, I didn't.
<ngx-datatable class="table-zenmoov" [columnMode]="'force'" [rows]="rows" [rowHeight]="'auto'"
[headerHeight]="'auto'" [footerHeight]="'auto'" [externalPaging]="true" [count]="paginationInfo.totalElements"
[loadingIndicator]="loadingIndicator"
[offset]="paginationInfo.currentPage" [limit]="paginationInfo.pageSize" (page)="setTablePage($event)"
(sort)="onSort($event)">
<ngx-datatable-column name="Name" [prop]="'first_name'" [sortable]="true">
<ng-template let-row="row" ngx-datatable-cell-template>
<div class="user-wrap">
<div class="zenmoov-vendor" [style.background]="row.company_id?'#f0ad4e':'#5bc0de'"></div>
<div class="img-circle img-wrapper vendor-avatar">
<img *ngIf="row.avatar_url" [src]="row?.avatar_url " alt="logo">
</div>
<ng-container *ngIf="auth.userRID=='admin'">
<a [routerLink]="['../../vendor/',row._id]">{{ row?.first_name }} {{ row?.last_name }}</a>
</ng-container>
<ng-container *ngIf="auth.userRID=='hr'">
<a [routerLink]="['../../../vendor/',row._id]">{{ row?.first_name }} {{ row?.last_name }}</a>
</ng-container>
<ng-container *ngIf="auth.userRID=='talent'">
<a [routerLink]="['/talent/vendor/',row._id]">{{ row?.first_name }} {{ row?.last_name }}</a>
</ng-container>
</div>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Company" [sortable]="false">
<ng-template let-row="row" ngx-datatable-cell-template>
{{ row?.company_name }}
</ng-template>
</ngx-datatable-column>
</ngx-datable class>
You can use *ngIf on html element and it will be displayed only if the conditions are met.
I have never used ngx-datatable however, from a quick look into the documentation and your code I think I got it. I suppose that this bit [rows]="rows" is where you feed your data to the datatable, what you need to do is filter out the objects you don't want to be in the datatable, something like this in your TypeScript file:
TypeScript File
// Array of strings that contains all countries in America
const americaCountries = [...];
// Iterate over each row and verify if the country of that row is in the array americaCountries
// If it is, that row is added to a new array named americaRows
this.americaRows = this.rows.filter(row => americaCountries.includes(row.country));
HTML File
[rows]="americaRows"
Bear in mind that this is pseudo code because I don't know your TypeScript code and the rows object structure.

*ngIf else if in template

How would I have multiple cases in an *ngIf statement? I'm used to Vue or Angular 1 with having an if, else if, and else, but it seems like Angular 4 only has a true (if) and false (else) condition.
According to the documentation, I can only do:
<ng-container *ngIf="foo === 1; then first else second"></ng-container>
<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>
But I want to have multiple conditions (something like):
<ng-container *ngIf="foo === 1; then first; foo === 2; then second else third"></ng-container>
<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>
But I'm ending up having to use ngSwitch, which feels like a hack:
<ng-container [ngSwitch]="true">
<div *ngSwitchCase="foo === 1">First</div>
<div *ngSwitchCase="bar === 2">Second</div>
<div *ngSwitchDefault>Third</div>
</ng-container>
Alternately, it seems like a lot of the syntaxes I've got used to from Angular 1 and Vue aren't supported in Angular 4, so what would be the recommended way to structure my code with conditions like this?
Another alternative is to nest conditions
<ng-container *ngIf="foo === 1;else second"></ng-container>
<ng-template #second>
<ng-container *ngIf="foo === 2;else third"></ng-container>
</ng-template>
<ng-template #third></ng-template>
You can just use:
<ng-template [ngIf]="index == 1">First</ng-template>
<ng-template [ngIf]="index == 2">Second</ng-template>
<ng-template [ngIf]="index == 3">Third</ng-template>
unless the ng-container part is important to your design I suppose.
Here's a Plunker
This seems to be the cleanest way to do
if (foo === 1) {
} else if (bar === 99) {
} else if (foo === 2) {
} else {
}
in the template:
<ng-container *ngIf="foo === 1; else elseif1">foo === 1</ng-container>
<ng-template #elseif1>
<ng-container *ngIf="bar === 99; else elseif2">bar === 99</ng-container>
</ng-template>
<ng-template #elseif2>
<ng-container *ngIf="foo === 2; else else1">foo === 2</ng-container>
</ng-template>
<ng-template #else1>else</ng-template>
Notice that it works like a proper else if statement should when the conditions involve different variables (only 1 case is true at a time). Some of the other answers don't work right in such a case.
aside: gosh angular, that's some really ugly else if template code...
You can use multiple way based on sitaution:
If you Variable is limited to specific Number or String, best way is using ngSwitch or ngIf:
<!-- foo = 3 -->
<div [ngSwitch]="foo">
<div *ngSwitchCase="1">First Number</div>
<div *ngSwitchCase="2">Second Number</div>
<div *ngSwitchCase="3">Third Number</div>
<div *ngSwitchDefault>Other Number</div>
</div>
<!-- foo = 3 -->
<ng-template [ngIf]="foo === 1">First Number</ng-template>
<ng-template [ngIf]="foo === 2">Second Number</ng-template>
<ng-template [ngIf]="foo === 3">Third Number</ng-template>
<!-- foo = 'David' -->
<div [ngSwitch]="foo">
<div *ngSwitchCase="'Daniel'">Daniel String</div>
<div *ngSwitchCase="'David'">David String</div>
<div *ngSwitchCase="'Alex'">Alex String</div>
<div *ngSwitchDefault>Other String</div>
</div>
<!-- foo = 'David' -->
<ng-template [ngIf]="foo === 'Alex'">Alex String</ng-template>
<ng-template [ngIf]="foo === 'David'">David String</ng-template>
<ng-template [ngIf]="foo === 'Daniel'">Daniel String</ng-template>
Above not suitable for if elseif else codes and dynamic codes, you can use below code:
<!-- foo = 5 -->
<ng-container *ngIf="foo >= 1 && foo <= 3; then t13"></ng-container>
<ng-container *ngIf="foo >= 4 && foo <= 6; then t46"></ng-container>
<ng-container *ngIf="foo >= 7; then t7"></ng-container>
<!-- If Statement -->
<ng-template #t13>
Template for foo between 1 and 3
</ng-template>
<!-- If Else Statement -->
<ng-template #t46>
Template for foo between 4 and 6
</ng-template>
<!-- Else Statement -->
<ng-template #t7>
Template for foo greater than 7
</ng-template>
Note: You can choose any format, but notice every code has own problems
Or maybe just use conditional chains with ternary operator. if … else if … else if … else chain.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator#Conditional_chains
<ng-container [ngTemplateOutlet]="isFirst ? first : isSecond ? second : third"></ng-container>
<ng-template #first></ng-template>
<ng-template #second></ng-template>
<ng-template #third></ng-template>
I like this aproach better.
To avoid nesting and ngSwitch, there is also this possibility, which leverages the way logical operators work in Javascript:
<ng-container *ngIf="foo === 1; then first; else (foo === 2 && second) || (foo === 3 && third)"></ng-container>
<ng-template #first>First</ng-template>
<ng-template #second>Second</ng-template>
<ng-template #third>Third</ng-template>
you don't need to use *ngIf if you use ng-container
<ng-container [ngTemplateOutlet]="myTemplate === 'first' ? first : myTemplate ===
'second' ? second : third"></ng-container>
<ng-template #first>first</ng-template>
<ng-template #second>second</ng-template>
<ng-template #third>third</ng-template>
<ion-row *ngIf="cat === 1;else second"></ion-row>
<ng-template #second>
<ion-row *ngIf="cat === 2;else third"></ion-row>
</ng-template>
<ng-template #third>
</ng-template>
Angular is already using ng-template under the hood in many of the
structural directives that we use all the time: ngIf, ngFor and
ngSwitch.
> What is ng-template in Angular
https://www.angularjswiki.com/angular/what-is-ng-template-in-angular/
I came a cross this type of situation *ngIf elseIf else and I solved using ng-template, Hope the following snippet may depicts briefly,
I have a form control named "NIC" and need to show one error message at a time when the form control invalid.
form: FormGroup = new FormGroup({
NIC: new FormControl('', [Validators.required, Validators.minLength(10), Validators.maxLength(10), Validators.pattern("^[0-9]*$")])
});
Template
<mat-form-field appearance="standard">
<mat-label>NIC Number</mat-label>
<input matInput placeholder="Enter NIC no" formControlName="NIC">
<mat-error *ngIf="form.controls['NIC'].errors?.required; else minvalue">This field is mandatory.
</mat-error>
<ng-template #minvalue>
<mat-error *ngIf="form.controls['NIC'].errors?.minlength; else maxvalue">Minimum 10 charactors
needed.
</mat-error>
</ng-template>
<ng-template #maxvalue>
<mat-error *ngIf="form.controls['NIC'].errors?.maxLength; else numericonly">Maximum 10
charactors allowed.
</mat-error>
</ng-template>
<ng-template #numericonly>
<mat-error *ngIf="form.controls['NIC'].errors?.pattern">
Numeric characters only.
</mat-error>
</ng-template>
</mat-form-field>
If you have a straightforward case in which some variable can take several values (for example, foo is of 1 | 2 | 3 type) just use the plain ngSwitch:
<ng-container [ngSwitch]="foo">
<div *ngSwitchCase="1">First</div>
<div *ngSwitchCase="2">Second</div>
<div *ngSwitchCase="3">Third</div>
</ng-container>
However, if you need a more sophisticated if-else logic it may be better and clearer to describe it inside the component's code and then turn its result into one of the set of states:
getLandformType(): 'continent' | 'island' | 'peninsula' {
if(this.pieceOfLand.bigEnough){
return 'continent';
}
else if(this.pieceOfLand.surroundedByWater){
return 'island';
}
return 'peninsula';
}
which, again, can be handled through ngSwitch:
<ng-container [ngSwitch]="getLandformType()">
<div *ngSwitchCase="'continent'">Continent</div>
<div *ngSwitchCase="'island'">Island</div>
<div *ngSwitchCase="'peninsula'">Peninsula</div>
</ng-container>
This approach also ensures that only one option can win at once, in contrast to that with three different *ngIf (without elses) blocks.
You can also use this old trick for converting complex if/then/else blocks into a slightly cleaner switch statement:
<div [ngSwitch]="true">
<button (click)="foo=(++foo%3)+1">Switch!</button>
<div *ngSwitchCase="foo === 1">one</div>
<div *ngSwitchCase="foo === 2">two</div>
<div *ngSwitchCase="foo === 3">three</div>
</div>