How to link mat-progress bar with project id from mat-table - javascript

I have a Job Execution screen which displays list of Jobs and their status.
I want to create an Indeterminate mat-progress bar which will appear for Jobs which are executing and when the status of Job changes to stop or complete it should disappear.
I have created a progress bar but I cannot link it to mat-table id or status.
HTML Code:
<div class="main-content">
<mat-toolbar>
<mat-progress-bar
mode="indeterminate"
class="mat-progress-bar"
color="primary"
>
</mat-progress-bar>
<button
mat-icon-button
(click)="stop_exec_job(element)"
matTooltip="Stop Executing the Job"
>
<!-- Edit icon for row -->
<i class="material-icons" style="color:red"> stop </i>
</button>
</mat-toolbar>
<div class="card">
<div class="card-header">
<h5 class="title">Job Execution Stats</h5>
</div>
<mat-table [dataSource]="jobExecutionStat">
<!-- Id Column -->
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> ID </mat-header-cell>
<mat-cell *matCellDef="let element">{{ element.id }} </mat-cell>
</ng-container>
<ng-container matColumnDef="exec_date">
<mat-header-cell *matHeaderCellDef>
Execution Date
</mat-header-cell>
<mat-cell *matCellDef="let element"
>{{ element.exec_date }}
</mat-cell>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="curr_time_period">
<mat-header-cell *matHeaderCellDef>
Current Time Period
</mat-header-cell>
<mat-cell *matCellDef="let element"
>{{ element.curr_time_period }}
</mat-cell>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="prev_time_period">
<mat-header-cell *matHeaderCellDef>
Previous Time Period
</mat-header-cell>
<mat-cell *matCellDef="let element"
>{{ element.prev_time_period }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="status">
<mat-header-cell *matHeaderCellDef> Status </mat-header-cell>
<mat-cell *matCellDef="let element"
>{{ element.status }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions">
<mat-header-cell *matHeaderCellDef> </mat-header-cell>
<mat-cell *matCellDef="let element; let index = index">
<button
mat-icon-button
(click)="stop_exec_job(element)"
matTooltip="Stop Executing the Job"
[disabled]="element.status == 'Completed'"
>
<!-- Edit icon for row -->
<i class="material-icons" style="color:red"> stop </i>
</button>
<!-- Delete icon for row -->
<button
mat-icon-button
(click)="re_run_job(element)"
matTooltip="Re-Run the Job"
[disabled]="
element.status == 'Running' ||
element.status == 'Pending'
"
>
<i class="material-icons" style="color:green">
cached
</i>
</button>
</mat-cell>
</ng-container>
<mat-header-row
*matHeaderRowDef="jobExecStatDisplayedColumns"
></mat-header-row>
<mat-row *matRowDef="let row; columns: jobExecStatDisplayedColumns">
</mat-row>
</mat-table>
</div>
Typescript Code:
import { Component, OnInit } from "#angular/core";
import { MatTableDataSource } from "#angular/material";
import { GlobalAppSateService } from "../../services/globalAppSate.service";
import { DataService } from "../../services/data.service";
import { SnakBarComponent } from "../custom-components/snak-bar/snak-
bar.component";
#Component({
selector: "app-job-execution-screen",
templateUrl: "./job-execution-screen.component.html",
styleUrls: ["./job-execution-screen.component.scss"]
})
export class JobExecutionScreenComponent implements OnInit {
jobExecStatDisplayedColumns = [
"id",
"exec_date",
"prev_time_period",
"curr_time_period",
"status",
"actions"
];
jobExecutionStat = new MatTableDataSource<Element>(ELEMENT_DATA);
constructor(
private dataService: DataService,
public globalAppSateService: GlobalAppSateService,
private snakbar: SnakBarComponent
) {}
ngOnInit() {
const project = JSON.parse(this.dataService.getObject("project"));
if (project != null) {
this.globalAppSateService.onMessage(project);
}
}
stop_exec_job(element) {
if(element.status == 'Running') {
this.snakbar.statusBar('Job Execution Stopped','Sucess');
}
}
re_run_job(element) {
if(element.status == 'Completed') {
this.snakbar.statusBar('Job Execution Started','Sucess');
}
}
}
const ELEMENT_DATA: Element[] = [
{
id: 1,
exec_date: "17-01-2016",
prev_time_period: "2016-04,2016-05,2016-06",
curr_time_period: "2016-08",
status: "Completed"
},
{
id: 2,
exec_date: "17-01-2017",
prev_time_period: "2017-04,2017-05,2017-06",
curr_time_period: "2017-08",
status: "Running"
},
{
id: 3,
exec_date: "27-07-2017",
prev_time_period: "2017-45,2017-46,2017-47",
curr_time_period: "2018-01,2018-02",
status: "Pending"
},
{
id: 4,
exec_date: "17-10-2018",
prev_time_period: "2017-30,2017-31,2017-32",
curr_time_period: "2018-01,2018-02",
status: "Completed"
},
{
id: 5,
exec_date: "21-01-2018",
prev_time_period: "2016-01,2016-02,2016-03,2016-04",
curr_time_period: "2016-52",
status: "Pending"
},
{
id: 6,
exec_date: "17-01-2018",
prev_time_period: "2017-31,2017-32,2017-33,2017-34",
curr_time_period: "2017-52",
status: "Running"
}
];
export interface Element {
id: number;
exec_date: string;
prev_time_period: string;
curr_time_period: string;
status: string;
}
Link for stackblitz

Stop button that is placed next to Job Name is working because the element variable is valid(i.e. inside mat-table tag).
But it's not working for Stop button next to Progress bar because the element variable is undefined/not valid(i.e. Outside of mat-table tag). That's why its giving error like 'TypeError: Cannot read property 'status' of undefined.'

Related

How to pass list of objects from angular component to html template created in material design

I have method getReports in my angular component where I subscribe to endpoint which looks like list of objects after console log, and where I want to display form, until issi, status for every report that I have in my list. But seems that I didn't properly passed data from component to html, I also use material ui for design.
{
"content": [
{
"id": 1,
"from": "2022-03-14T23:00:00",
"until": "2022-03-15T13:37:00",
"issi": "1500",
"format": "KML",
"creationDate": "2023-01-19T11:53:40.018808",
"status": "DOWNLOADABLE"
},
{
"id": 2,
"from": "2022-03-14T23:00:00",
"until": "2022-03-15T13:37:00",
"issi": "1500",
"format": "KML",
"creationDate": "2023-01-19T11:54:23.810516",
"status": "DOWNLOADABLE"
},
{
"id": 3,
"from": "2022-03-14T23:00:00",
"until": "2022-03-15T13:37:00",
"issi": "1500",
"format": "CSV",
"creationDate": "2023-01-19T11:55:24.018175",
"status": "DOWNLOADABLE"
},
],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 25,
"unpaged": false,
"paged": true
},
"totalPages": 1,
"totalElements": 12,
"last": true,
"size": 25,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"first": true,
"numberOfElements": 12,
"empty": false}
here is my component
import {Component, ViewChild, AfterViewInit, Input} from '#angular/core';
import {MatPaginator} from '#angular/material/paginator';
import {ReportInterface} from "../../types/ReportInterface";
import {MatTableDataSource} from "#angular/material/table";
import {ReportsService} from "../../services/reports.service";
import {saveAs} from "file-saver";
#Component({
selector: 'app-reports-table',
templateUrl: './reports-table.component.html',
styleUrls: ['./reports-table.component.scss']
})
export class ReportsTableComponent implements AfterViewInit {
public displayedColumns: string[] = ['createdAt', 'from', 'until', 'devices', 'status', 'action'];
#Input() data: ReportInterface[] = [];
dataSource!: MatTableDataSource<any>;
// #ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private reportsService: ReportsService) {
}
ngOnInit(): void {
this.getReports();
}
ngAfterViewInit(): void {
// this.dataSource.paginator = this.paginator;
}
downloadReport(id: number, format: 'CSV' | 'KML') {
this.reportsService.downloadReport(id).subscribe((buffer) => {
const data: Blob = new Blob([buffer], {
type: "text/csv;charset=utf-8"
});
if (format === 'CSV') {
return saveAs(data, "report-" + id + ".csv");
}
return saveAs(data, "report-" + id + ".kml");
});
}
getReports() {
this.reportsService.getAllReports().subscribe({
next: (element:ReportInterface[]) => {
this.dataSource = new MatTableDataSource(element);
console.log('aco',element);
},
error: (err) => {
alert('Error while fetching users');
},
});
}
}
and also my HTML template
<table mat-table [dataSource]="dataSource" class="reports-table">
<!-- Create at Column -->
<ng-container matColumnDef="createdAt">
<th mat-header-cell *matHeaderCellDef> Created at </th>
<td mat-cell *matCellDef="let element"> {{element.creationDate | date: 'd/M/yy - H:mm'}} </td>
</ng-container>
<!-- From Column -->
<ng-container matColumnDef="from">
<th mat-header-cell *matHeaderCellDef> From </th>
<td mat-cell *matCellDef="let element"> {{element.from | date: 'd/M/yy - H:mm'}} </td>
</ng-container>
<!-- Until Column -->
<ng-container matColumnDef="until">
<th mat-header-cell *matHeaderCellDef> To </th>
<td mat-cell *matCellDef="let element"> {{element.until | date: 'd/M/yy - H:mm'}} </td>
</ng-container>
<!-- Status Column -->
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let element"> {{element.status.toLowerCase()}} </td>
</ng-container>
<!-- Devices Column -->
<ng-container matColumnDef="devices">
<th mat-header-cell *matHeaderCellDef> Devices </th>
<td mat-cell *matCellDef="let element"> {{element.issi}} </td>
</ng-container>
<!-- Actions Column -->
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef> Action </th>
<td mat-cell *matCellDef="let element">
<button mat-button class="download-button" (click)="downloadReport(element.id, element.format)">Download in {{element.format}}</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<mat-paginator [pageSizeOptions]="[5, 10, 20]"
showFirstLastButtons
aria-label="Select page of periodic elements">
</mat-paginator>
</table>

Add formData to datasource array of objects angular

I am trying to push edited form data from edit-customers-dialog.ts to an array of objects in my datasource. The form.data.value comes back correctly, but it is not being inserted into the array properly.
I am having trouble finding the correct syntax on pushing to an interface data type. Please help as I'm new to angular. Thanks!
customers.html
  <mat-card-title>    
    <button id="invite" mat-raised-button color="primary" type="button" (click)="addCustomer()">
      Add Customer
    </button>
  </mat-card-title>
<mat-card-content>
<table mat-table [dataSource]="dataSource.data" class="mat-elevation-z8">
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
</ng-container>
<!-- Address Column -->
<ng-container matColumnDef="address">
<th mat-header-cell *matHeaderCellDef> Address </th>
<td mat-cell *matCellDef="let row"> {{row.address}}</td>
</ng-container>
<!-- Actions Column -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let row">
<ng-container>
<button id="edit" mat-icon-button color="primary" title="Update Customer" (click)="editCustomer(row)" >
<mat-icon>edit</mat-icon>
</button>
<button id="delete" mat-icon-button color="warn" title="Delete Customer" (click)="deleteCustomer(row)">
<mat-icon>delete</mat-icon>
</button>
</ng-container>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator
showFirstLastButtons
[length] = "0"
[pageSizeOptions]="[25, 50, 75]"
>
</mat-paginator>
</mat-card-content>
</mat-card>
customers.component.ts
import {MatTableDataSource} from '#angular/material/table';
import { MatPaginator } from '#angular/material/paginator';
import { MatSort } from '#angular/material/sort';
import { MatDialog, MatDialogConfig, MatDialogRef} from '#angular/material/dialog/';
import { AddCustomerDialogComponent } from '../customers/add-customer-dialog/add-customer-dialog.component';
import { EditCustomerDialogComponent } from '../customers/edit-customer-dialog/edit-customer-dialog.component';
import {CustomerDataSource, CustomerListItem } from './customer.datasource';
#Component({
selector: 'app-customers',
templateUrl: './customers.component.html',
styleUrls: ['./customers.component.css']
})
export class CustomersComponent implements OnInit {
#ViewChild(MatPaginator) paginator: MatPaginator;
#ViewChild (MatSort) sort: MatSort;
dataSource: CustomerDataSource;
customer: CustomerListItem [];
displayedColumns: string[]
constructor(
public dialog: MatDialog) {}
ngOnInit() {
this.displayedColumns = ['name', 'address', 'actions'];
this.dataSource = new CustomerDataSource (this.paginator, this.sort,
);
}
editCustomer(customer: CustomerListItem){
const dialogRef = this.dialog.open(EditCustomerDialogComponent, <MatDialogConfig> {
data: customer,
});
dialogRef.afterClosed()
.subscribe(result => {
this.dataSource.data.push({name, address: ''})
console.log('The dialog was closed');
console.log(this.dataSource.data);
});
}
deleteCustomer(customer: CustomerListItem){
if(confirm('Are you sure you want to delete this customer?'))
{
this.dataSource.data = this.dataSource.data.filter(person => person.name != customer.name);
}
}
}
edit-customer-dialog.html
<h2 mat-dialog-title>
Edit Customer
</h2>
<form *ngIf="form" [formGroup]="form" (ngSubmit)="onSubmitForm()">
<mat-dialog-content class="container">
<mat-form-field>
<input matInput placeholder="Name" formControlName ="name" required/>
</mat-form-field>
<mat-form-field class="input">
<input id="placeholder" matInput placeholder="Address" formControlName ="address" required/>
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
<button
id="add"
mat-button
mat-raised-button
color="primary"
type="submit"
>
Update
</button>
<button id="cancel" mat-button mat-raised-button color="warn" mat-dialog-close>Cancel</button>
</mat-dialog-actions>
</form>
edit-customer-dialog-comptent.ts
import { Component, OnInit, Inject } from '#angular/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '#angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef} from '#angular/material/dialog/';
import {MatTableDataSource} from '#angular/material/table';
import { MatPaginator } from '#angular/material/paginator';
import { CustomerDataSource, CustomerListItem } from '../customer.datasource';
#Component({
selector: 'app-edit-customer-dialog',
templateUrl: './edit-customer-dialog.component.html',
styleUrls: ['./edit-customer-dialog.component.css']
})
export class EditCustomerDialogComponent implements OnInit {
form: FormGroup;
customer: CustomerListItem [];
constructor(
#Inject (MAT_DIALOG_DATA) public data: any,
private dialogRef: MatDialogRef<EditCustomerDialogComponent>,
private formBuilder: FormBuilder
) {}
ngOnInit() {
// Intitlaize the form
this.form = this.formBuilder.group({
name: this.data.name,
address: this.data.address
})
console.log(this.form.value);
}
onSubmitForm(){
// Update Customer
console.log(this.form.value);
this.dialogRef.close(this.form.value);
}
}
datasource array:
export interface CustomerListItem {
name: string;
address: string;
}
// TODO: replace this with real data from server
const EXAMPLE_DATA: CustomerListItem[] = [
{ name: 'Michael Jordan', address: '1111 Grail St. Concord MI 98076' },
{ name: 'Jeremy Scott', address: '7690 Wing Drive. Adidas, MI' },
{ name: 'Hiroki Nakamura', address: '980 Air Force Rd. Jubilee, MI' },
{ name: 'James Bond', address: '654 Depop Dr. Chicago, MI' },
{ name: 'Bill Bowerman', address: '1811 Hill St. Converse, MI' },
{ name: 'Clyde Frazier', address: '3333 Cement Ln. Jordan, MI'},
{ name: 'Jeff Staple', address: '4444 Black Cat Ct. Jordan,MI' },
{ name: 'Sophia Chang', address: '2006 Citrus Rd. Seven, MI'},
];
Add let i = index and pass i to the edit function
<td mat-cell *matCellDef="let row; let i = index;">
<ng-container>
<button id="edit" mat-icon-button color="primary" title="Update Customer" (click)="editCustomer(row, i)" >
<mat-icon>edit</mat-icon>
</button>
</ng-container>
</td>
editCustomer(customer: CustomerListItem, i: number){
}
Try reinitializing the data after the edit.
this.dataSource.data[i] = result;
this.dataSource.data = this.dataSource.data;
OR
const temp = this.dataSource.data;
temp[i] = result;
this.dataSource.data = temp;

Vuetify v-simple-table Highlight Selected Row

Been reading the docs in Vutify for their v-simple-table and v-data-table and I am trying to figure out if there is a way to add a row highlight like you can for a v-data-table.
Such as this?
Vuetify - How to highlight row on click in v-data-table
My table body looks like this:
<v-simple-table dense fixed-header height="90vh" >
<template v-slot:default>
<thead >
<tr >
<th style="font-size: 16px;height: 40px;" width='4%' class="black--text">
Location
</th>
<template v-if="Object.keys(arrAvailableDates).length">
<th style="font-size: 17px; " class="text-center black--text" v-for="(strDate, intIndex) in arrAvailableDates" :key="intIndex">
<span> {{ $moment(strDate).format('D MMM (ddd)') }}</span>
<v-badge tile v-if="total[strDate] > 0" inline color="green" v-bind:content="total[strDate]" > </v-badge>
</th>
</template>
<template v-else>
<th class="text-center" v-for="intHeaderCounter in 6" :key="intHeaderCounter">
<v-skeleton-loader
:key="intHeaderCounter"
type='text'
></v-skeleton-loader>
</th>
</template>
</tr>
</thead>
<tbody v-if="!blnLoading">
<template v-if="Object.keys(arrFiltered).length" >
<tr class="teal lighten-5"
v-for="(arrData, strLocationName) in arrFiltered"
:key="'f-' + strLocationName"
>
<th class="black--text text-darken--3">
{{ strLocationName }} <br/><span class="caption">{{arrData['zip']}}</span>
</th>
<template v-for="(arrAppointmentData, strDate) in arrData['appointment']">
<td :key="strDate" class="text-center ma-0 pa-0" >
<template v-if="typeof(arrAppointmentData) == 'object' ">
<span class="time-slot-x-small" v-for='(intCount, intIndex) in arrAppointmentData' :key="intIndex">
{{ $moment(intIndex, ["HH:mm:ss"]).format('hh:mma')}}
<span class="dot">{{intCount}}</span>
</span>
</template>
<template v-else>
-
</template>
</td>
</template>
</tr>
</template>
I can hover a row and it will show that the row is been hover but I am trying to create a way where if I click on the row, it will change the background color when selected.
An example I am trying to mirror is like this but with a simple table:
https://www.codeply.com/p/hi40H9aug9
Here is a more Vue centric approach...
template:
<tbody>
<tr
v-for="(item,idx) in items"
:key="item.name"
#click="handleClick(idx)"
:class="{ selected: selected.includes(idx) }"
>
<td>{{ item.name }}</td>
<td>{{ item.calories }}</td>
</tr>
</tbody>
script:
data () {
return {
items: [
{
id: 1,
name: "Frozen Yogurt",
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
iron: "1%",
},
],
selected: [],
}
},
methods: {
handleClick(i) {
let pos = this.selected.indexOf(i)
if (pos > -1) {
this.selected.splice(pos, 1);
}
else {
this.selected.push(i)
}
},
}
https://codeply.com/p/PaV3dwWk1j

Expand ngx-datatable on view load

Have the below ngx-datatable where I want to have the first row expanded on view load. I have tried to call the toggleExpandRow(this.table.row[0]) on the angular lifecycle hook ngAfterViewChecked and the template is not getting updated with the row expanding. Has anyone accomplished this before with ngx-datatable? The below code does not run and is there for information purposes only.
import {
Component,
Input,
Output,
EventEmitter,
OnInit,
ChangeDetectionStrategy,
ViewEncapsulation,
ViewChild
} from '#angular/core';
import { defaultTrackByFn } from '#shared/utils';
import { Datatable } from '#app/stores/dashboard-store/models/datatable.model';
import { DatatableComponent as ngxDatatableComponent } from '#swimlane/ngx-datatable';
import { Observable } from 'rxjs';
import { ActiveToggleService } from '#dashboard/services/ActiveToggle.service';
#Component({
selector: 'fmsl-datatable',
templateUrl: './datatable.component.html',
styleUrls: ['./datatable.component.scss'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DatatableComponent implements OnInit {
#Input()
datatable: Datatable;
#Input()
isBorrower: boolean;
#ViewChild('loanTable')
table: ngxDatatableComponent;
#Input()
showLegend: boolean = true;
trackByFn: Function = defaultTrackByFn;
// TODO: Implement Datatable Actions
actions = ['replace with logic later'];
isBorrower$: Observable<boolean>;
constructor(private _toggleService: ActiveToggleService) {}
ngOnInit() {
// console.log('table:', this.table)
// console.log('table row detail', this.table.rowDetail)
// this.table.rowDetail.expandAllRows();
}
ngAfterViewChecked() {
console.log('table:', this.table)
console.log('table row detail', this.table.rowDetail)
console.log('table row:', this.table._rows[0])
this.table.rowDetail.toggleExpandRow(this.table._rows[0]);
}
toggleExpandRow(row) {
console.log('row toggled', row);
console.log('row table', this.table);
this.table.rowDetail.toggleExpandRow(row);
}
onDetailToggle(event) {
// on row detail expand we can do something
}
toggleActiveInactive(row) {
const { uuid, loanStatusTypeName } = row;
this._toggleService.toggleActiveInactive({ uuid, loanStatusTypeName });
}
}
<div class="row datatable-row">
<div class="col">
<!--mdc-replace datatable-->
<div [ngClass]="datatable.tableClass">
<!-- {{ datatable | json }} -->
<ngx-datatable
#loanTable
class="material expandable"
[rows]="datatable.rows"
[columnMode]="'flex'"
rowHeight="auto"
sortType="single"
[headerHeight]="42"
[footerHeight]="0"
[scrollbarH]="true"
[footerHeight]="0"
[loadingIndicator]="datatable.loading"
[messages]="datatable.messages"
>
<ngx-datatable-row-detail [rowHeight]="44" (toggle)="onDetailToggle($event)">
<ng-template
let-row="row"
let-expanded="expanded"
ngx-datatable-row-detail-template
>
<div class="expansion-row" style="padding-left:35px;">
<mdc-icon class="material-icons" aria-hidden="true">info_outline</mdc-icon>
<span
[innerHTML]="row.statusProperties.statusDetail"
class="datatable__expansion-row-message"
></span>
</div>
</ng-template>
</ngx-datatable-row-detail>
<ngx-datatable-column
[width]="50"
[resizeable]="false"
[sortable]="false"
[draggable]="false"
[canAutoResize]="false"
>
<ng-template let-row="row" let-expanded="expanded" ngx-datatable-cell-template>
<a
href="javascript:void(0)"
[class.datatable-icon-right]="!expanded"
[class.datatable-icon-down]="expanded"
title="Expand/Collapse Row"
(click)="toggleExpandRow(row)"
>
</a>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
*ngFor="let col of datatable.columns; index as i; trackBy: trackByFn"
[name]="col.name"
resizeable="false"
[flexGrow]="col.flex"
[prop]="col.prop"
[pipe]="col.pipe"
>
<ng-template let-column="column" ngx-datatable-header-template let-expanded="true">
{{ col.name }}
</ng-template>
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
<div class="table-cell justify-content-start" [attr.data-heading]="col.name">
<span *ngIf="col.isIcon; else progressCell">
<fmsl-datatable-icon
*ngIf="value"
[actionRequiredBy]="value"
[legend]="datatable.legend"
[currentRole]="datatable.currentRole"
></fmsl-datatable-icon>
</span>
<div *ngIf="col.isActions" class="rowActions">
<button mdc-button (click)="toggleActiveInactive(row)">
Mark {{ row.loanStatusTypeName === 'active' ? 'Inactive' : 'Active' }}
</button>
</div>
<ng-template #progressCell>
<div *ngIf="col.isProgress; else linkCell" class="progress-container">
<mdc-linear-progress
class="progress-bar loan-status-progress-bar"
[determinate]="true"
[progress]="value"
></mdc-linear-progress>
</div>
</ng-template>
<ng-template #linkCell>
<span *ngIf="col.isLink; else valueCell">
<a
*ngIf="row.sharePointURL; else internalLink"
target="_blank"
href="{{ row.sharePointURL }}"
>{{ value }}
</a>
<ng-template #internalLink>
<a [routerLink]="['/dashboard/deal', 'loan-request-info', row.uuid]">{{
value
}}</a>
</ng-template>
</span>
</ng-template>
<ng-template #valueCell>
<span>{{ value }}</span>
</ng-template>
</div>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</div>
</div>
There is an open issue https://github.com/swimlane/ngx-datatable/issues/929 while using toggle functions with onInit and afterViewInit hooks.
To call toggle function inside ngAfterViewChecked is not a good idea, as this hook will be called multiple times. And once you get it expanded, you cannot collapse it.
Still there is a dirty workaround to call the toggle function inside AfterViewInit within setTimeout:
#ViewChild(DatatableComponent) private table: DatatableComponent;
constructor(private cdRef: ChangeDetectorRef) {}
setTimeout(() => {
this.table.rowDetails.toggleExpandedRow(ROW);
this.cdRef.detectChanges();
}, 1000);

angular2 Can't have multiple template bindings on one element

I have this angular2 template:
<template *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</template>
I get these errors:
zone.js:461 Unhandled Promise rejection: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * (" </div>
<div *ngSwitchCase="false" class="container p-t-10">
<alert *ngIf="alerts.length > 0" [ERROR ->]*ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert"): b#5:37
what's the problem I put *ngIf and *ngFor in defferent html elements. It should work. no?
and:
Can't bind to 'type' since it isn't a known property of 'alert'. (""container p-t-10">
<alert *ngIf="alerts.length > 0" *ngFor="let alert of alerts;let i = index" [ERROR ->][type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
"): b#5:80
I added the
*ngIf="alerts.length > 0 to avoid cases of alert = []. How can i fix it otherwise?
The * in *ngFor makes Angular to add a <template> tag. On a <template> tag this doesn't make sense and therefore here structural directives have a different syntax.
<template ngFor [ngForOf]="alerts" let-alert let-i="index">
Because different syntax for almost the same on different places caused quite some confusion, the Angular team recently introduced
<ng-container>
that behaves similar to the <template> tag (is not added to the DOM) but allows the more common syntax
<ng-container *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</ng-container>
You should use <ng-container> for this case. As a example:
<ng-container *ngIf="totalItems > 0">
<tr *ngFor="let item of outputs| paginate: { id:'ab', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>
<ng-container *ngIf="totalItems > 10">
<tr *ngFor="let item of outputs| paginate: { id:'aabbbbbbbbb', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>

Categories

Resources