I've followed the Angular docs here https://angular.io/api/common/NgIf to create an NgIf else conditional over my Material Table. It is reading remote JSON file as API.
The API is twitter data and one of the fields I want to run condition on is 'replies'. If there are no replies, I want to replace the "0" with a "-".
I am getting the error
Can't have multiple template bindings on one element. Use only one attribute prefixed with * (" Replies
]*ngIf="hashtags.replies<1; else noReplies"> {{hashtags.replies}}
"):`
So it seems I cannot run NgIf and interpolate my data in the same element, I've tried all kinds of combinations in the HTML but I am real stuck.
HTML
<ng-container matColumnDef="replies">
<th mat-header-cell *matHeaderCellDef> Replies </th>
<td mat-cell *matCellDef="let hashtags" *ngIf="hashtags.replies<1; else noReplies"> {{hashtags.replies}} </td>
<ng-template #noReplies>-</ng-template>
</ng-container>
Try
<ng-container matColumnDef="replies">
<th mat-header-cell *matHeaderCellDef> Replies </th>
<ng-container *matCellDef="let hashtags">
<td mat-cell *ngIf="(hashtags.replies>0); else noReplies"> {{hashtags.replies}} </td>
</ng-container>
<ng-template #noReplies>-</ng-template>
</ng-container>
The reason for getting this error is because your can't put 2 structural directives on the same DOM
In your code, you were using *matCellDef and *ngIf on the same <td>.
you can do it this way...... xd
<ng-container matColumnDef="estadoRevision">
<mat-header-cell *matHeaderCellDef mat-sort-header>Revision</mat-header-cell>
<mat-cell *matCellDef="let element">
<td *ngIf="element.a === 0"> ejemplo </td>
<td *ngIf="element.a === 1"> ejemplo </td>
</mat-cell>
</ng-container>
Is there any reason you can't do the conditional directly in the interpolation?
<td mat-cell *matCellDef="let hashtags">{{hashtags.replies > 0 ? hashtag.replies : '-'}}</td>
Related
I have a variable in my ts that contains a value of 3 (array length), I want to use it in my html to increment the value of index ([0]) until the value of 3 is reached.
<table mat-table [dataSource]="dataSourceQuizOverview" matSort>
<ng-container matColumnDef="question_text">
<th class="font" mat-header-cell *matHeaderCellDef mat-sort-header>Questions</th>
<td class="font" mat-cell *matCellDef="let row">{{row.quiz_records[0].question_text}}</td>
</ng-container>
<ng-container matColumnDef="user_answers">
<th class="font" mat-header-cell *matHeaderCellDef mat-sort-header>Answer</th>
<td class="font" mat-cell *matCellDef="let row">{{row.quiz_records[0].user_answers}}</td>
</ng-container>
</table>
ts
quiz_recordsLength.length: number = 3;
You should check, NgForOf Directive. This should solve your issue.
Also, for future questions, please remember this: How much research effort is expected of stack overflow. Posting a new question should be your last resort.
I have this code:
<ng-container matColumnDef="Estado">
<th mat-header-cell *matHeaderCellDef>Estado</th>
<td mat-cell *matCellDef="">
<mat-checkbox *ngIf=!state mat-checked></mat-checkbox>
</td>
</ng-container>
When the condition in the *ngIf is met the checkbox appears unchecked, but I need to get it already checked, I don't know how, hope you can help me, thank you.
The mat-checkbox component has a input called 'checked'
Try something like that:
<ng-container matColumnDef="Estado">
<th mat-header-cell *matHeaderCellDef>Estado</th>
<td mat-cell *matCellDef="">
<mat-checkbox *ngIf="!state" [checked]="true"></mat-checkbox>
</td>
</ng-container>
It's always a good idea to check the API tab in the documentation of the component you are using
You need an ngModel to with a variable set to true if you want the checkbox to default in as true. Then, if you ever check/uncheck the checkbox, the current true/false value will be saved in your variable
ts
estadoFlag: boolean = true;
html
<ng-container matColumnDef="Estado">
<th mat-header-cell *matHeaderCellDef>Estado</th>
<td mat-cell *matCellDef="">
<mat-checkbox *ngIf=!state [(ngModel)]="estadoFlag"></mat-checkbox>
</td>
</ng-container>
As show below code i want to add space after every value in listing in angular. This data are come in table view.
In HTML file
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType}} </td>
</ng-container>
In ts file
bindTableCol() : void {
if(DNHelper.loginUserData && DNHelper.loginUserData.resourcePreference1 && DNHelper.loginUserData.resourcePreference1.length > 0){
this.displayedColumns = DNHelper.getColumnTable(DNHelper.loginUserData.resourcePreference1);
this.displayedColumns.push('view_more');
this.displayedColumns.push('action');
} else {
this.displayedColumns = ['divisonName', 'categoryName', 'rType', 'resourceStatus', 'view_more', 'action'];
}
}
In Result (These are values)
CRWT1,CRWT2IA,CRWT2,CRWT3,ENG1
Expected Result
CRWT1, CRWT2IA, CRWT2, CRWT3, ENG1
There snap of generated html
To minimize the load on your application, you might also consider creating a pipe.
It could look something like this, as far as usage: <p>{{ element.rType|join:', ' }}</p>.
The transform function would look like this:
#Pipe({
name: 'join'
})
export class JoinPipe implements PipeTransform {
transform(input:Array<any>, sep = ','): string {
return input.join(sep);
}
}
You can try this :
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType.split(",").join(", ")}} </td>
</ng-container>
Use this code It will help you.
<ng-container matColumnDef="rType">
<th mat-header-cell *matHeaderCellDef > Resource Type </th>
<td mat-cell *matCellDef="let element"> {{element.rType.replaceAll(',',', '}} </td>
</ng-container>
I am trying to sort a mat-table using the mat-sort-header. I am able to do it with common attributes like string or number.
<table #tablaClientes mat-table [dataSource]="dataSource" matSort multiTemplateDataRows>
<!-- Id Column -->
<ng-container matColumnDef="idIngreso">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Id Comprobante</th>
<td mat-cell *matCellDef="let row">{{row.idIngreso}}</td>
</ng-container>
<!-- Proveedor Column -->
<ng-container matColumnDef="idProveedor">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Nombre Proveedor</th>
<td mat-cell *matCellDef="let row">{{row.idProveedor.nombre}}</td>
</ng-container>
<!-- Fecha Compra Column -->
<ng-container matColumnDef="fechaCompra">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Fecha de Compra</th>
<td mat-cell *matCellDef="let row">{{row.fechaCompra}}</td>
</ng-container>
<!-- Fecha Recepcion Column -->
<ng-container matColumnDef="fechaRecepcion">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Fecha de Recepcion</th>
<td mat-cell *matCellDef="let row">{{row.fechaRecepcion}}</td>
</ng-container>
<!-- Monto Total Column -->
<ng-container matColumnDef="totalIngreso">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Monto Total</th>
<td mat-cell *matCellDef="let row">{{row.totalIngreso |currency}}</td>
</ng-container>
However I can't sort by idProveedor since it's an object.
Thank you very much!
The easer way is add to your dataSource a new property and sort by this new property like this SO (really if you don't need the "idProveedor" object, your dataSource can be transform to some like
this.data.forEach(x=>{
x.proveedorNombre=x.idProveedor.nombre
delete x.idProveedor
}
Another solution is create a sortingDataAccesor
this.dataSource.sortingDataAccessor = (item, property) => {
if (property=="idProveedor")
return item.nombre;
if (property=="idIngreso")
return item.idIngreso
if (property=="fechaCompra")
return item.fechaCompra
...
}
An example simple in this stackblitz
I am trying to make reusable material table and I want to use TemplateRef with ngTemplateOutlet to generate columns. In this example I created cards components which is using my material-table component. In cards.component.html I have template of one of my table's column. Running the project will cause an error ERROR TypeError: Cannot read property 'template' of undefined (see console on stackblitz). Is it possible to pass columnt template to my MaterialTableComponent and use it to define column?
<table mat-table [dataSource]="data" class="mat-elevation-z4">
<ng-container
*ngFor="let column of displayedColumnObjects"
[matColumnDef]="column.id"
>
<!-- if where is cellTemplate in table config json, use cellTemplate -->
<ng-container
*ngIf="column.cellTemplate"
[ngTemplateOutlet]="column.cellTemplate"
>
</ng-container>
<ng-container *ngIf="!column.cellTemplate">
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element"> {{element[column.id]}} </td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>
UPDATE
I found solution using ngTemplateOutletContext.
<table mat-table [dataSource]="data" class="mat-elevation-z4">
<ng-container
*ngFor="let column of displayedColumnObjects"
[matColumnDef]="column.id"
>
<ng-container
*ngIf="column.cellTemplate"
>
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element">
<ng-template
[ngTemplateOutletContext]="{
element: element[column.id]
}"
[ngTemplateOutlet]="column.cellTemplate">
</ng-template>
</td>
</ng-container>
<ng-container *ngIf="!column.cellTemplate">
<th mat-header-cell *matHeaderCellDef> {{column.title}} </th>
<td mat-cell *matCellDef="let element"> {{element[column.id]}} </td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>
See my example
ADD THE FOLLOWING IN THE COMPONENT TO BE RE-USED
In the '.HTML' file:
<ng-container [ngTemplateOutlet] = "yourNameReference"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Arthur', lastName: 'Lemos'}">
</ng-container>
[NgTemplateOutletContext] data will be sent to the parent component. Remembering that '$ implicit' can receive any data you want to send to the PAI component
In the '.ts' file OF THE REUSABLE COMPONENT add the following code WITHIN YOUR CLASS
#ContentChild ('yourNameReference') yourNameReference: TemplateRef <any>;
FATHER COMPONENT (RECEIVES THE RE-USED COMPONENT)
Add the following code to the '.html' file
<ng-template #yourNameReference let-myDataa>
<p> {{myDataa.name}} {{myDataa.lastName}} </p>
</ng-template>
That way you can send data from the child component to the parent component, so you can create dynamic columns for your table.
Just follow the steps above, however, applying the specific columns of the table ... EX:
<td> <ng-container [ngTemplateOutlet] = "yourNameReference"
[ngTemplateOutletContext] = "{$ implicit: {name: 'Arthur', lastName: 'Lemos'}">
</ng-container> </td>
Add to the child's .ts:
#ContentChild ('yourNameReference') yourNameReference: TemplateRef <any>;
In the parent component:
<my-table>
...
<ng-template #yourNameReference let-myDataa>
<p> {{myDataa.name}} {{myDataa.lastName}} </p>
</ng-template>
<! - this content will be rendered inside the table ... ->
...
</my-table>
YOU CAN CREATE A REFERENCE NAME FOR EACH COLUMN, AND REPEAT THE PROCESS
ANGLE VERSION: 9
DOCUMENTATION: https://angular.io/api/common/NgTemplateOutlet
The documentation does not show the use of ngTemplateOutlet in different components, but it already helps in something.