How to make a function in angular 7 - javascript

I have a mat-table with 6 columns. In 5th column it shows the status of Job i.e Completed,Running or Pending.
I have created two buttons i.e Stop and Re-Run.
I want to write function that if job is completed then Stop button should be disabled and re-run should be enabled which means that the user should be able to re-run the completed job and if job is executing or pending(waiting to execute) then Stop button should be enabled and re-run should be disabled which means that the user should be able to stop the running Job.
Can someone help me ?
I have created a sample stackblitz here.
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()"
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()"
matTooltip="Stop Executing the Job"
>
<!-- Edit icon for row -->
<i class="material-icons" style="color:red"> stop </i>
</button>
<!-- Delete icon for row -->
<button
class="stop_btn"
mat-icon-button
color="#b71c1c"
(click)="re_run_job()"
matTooltip="Re-Run the Job"
>
<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 {
stop_btn: boolean = true;
re_run_btn: boolean = true;
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() {
}
re_run_job() {
}
}
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;
}
For some reason stop and cached are icons and in my visual studio i can see icons but in stackblitz I can't convert them to icons.
Just for reference stop in red color is Stop and cached in green color is re-run

Use disabled to disable the button or *ngIf to remove it from the DOM completely.
<button mat-icon-button [disabled]="isRunning" (click)="stop_exec_job()" matTooltip="Stop Executing the Job"></button>
<button mat-icon-button [disabled]="!isRunning" (click)="stop_exec_job()" matTooltip="Stop Executing the Job"></button>
Update the state based on what action was executed. Be sure to set the correct initial state as well.
isRunning: boolean = false;
stop_exec_job() {
this.isRunning = false;
}
re_run_job() {
this.isRunning = true;
}

If you want to disable buttons in your table you will have to use disabled attribute and make a check with your element status.
[disabled]="element.status === 'Completed'" // The button will be disabled if status is Completed
[disabled]="element.status === 'Running'" // Disabled if status is Running
Considering your criteria, your Stop button will look like this:
<button
[disabled]="element.status === 'Completed'"
mat-icon-button
(click)="stop_exec_job()"
matTooltip="Stop Executing the Job"
>
<!-- Edit icon for row -->
<i class="material-icons" style="color:red"> stop </i>
</button>
And your ReRun button will be like:
<button
[disabled]="element.status === 'Running'"
class="stop_btn"
mat-icon-button
color="#b71c1c"
(click)="re_run_job()"
matTooltip="Re-Run the Job"
>
<i class="material-icons" style="color:green">
cached
</i>
</button>

Related

Angular mat-table displaying repeat rows

I am trying to create a relatively simple mat-table that displays elements from a "dataSource". My problem is that when I run my code it gives me the error: There can only be one default row without a when predicate function.
Adding multiTemplateDataRows to my <mat-table> fixes this problem but makes it so that all of the elements in my table are duplicated (two of them).
Picture displaying duplication
I want to understand why is is happening. I believe that in my case the items are duplicated because I have exactly two columns. Can someone help me understand?
My Code:
HTML:
<mat-table [dataSource]="siteContacts" multiTemplateDataRows class="table" fxLayout="column wrap">
<ng-container [matColumnDef]="col" *ngFor="let col of siteContactColumns">
<mat-header-cell *matHeaderCellDef>
</mat-header-cell>
<mat-cell *matCellDef="let element">
<div [ngSwitch]="siteContactDataSchema[col]">
<div *ngSwitchCase="'ContactTitle'">
{{element[col]}}
</div>
<span *ngSwitchDefault>
{{element[siteContactDataSchema[col][0]]}} <br>
{{element[siteContactDataSchema[col][1]]}} <br>
{{element[siteContactDataSchema[col][2]]}}
</span>
</div>
</mat-cell>
<mat-row *matRowDef="let row; let even = even; columns: siteContactColumns;" [ngClass]="{gray: even}">
</mat-row>
</ng-container>
</mat-table>
Typescript:
const SITE_CONTACTS_SCHEMA = {
"ContactTitle": "ContactTitle",
"ContactInfo": ["ContactName", "ContactCellPhone", "ContactEmail"]
}
...
siteContactDataSchema = SITE_CONTACTS_SCHEMA;
siteContactColumns: string[] = ['ContactTitle', 'ContactInfo'];
...
this.siteDirectoryService.getAllSiteContacts(this.parentSiteId).subscribe(res => {
this.siteContacts = res;
})

Angular nativeElement offsetTop alway 0

Im working in a menu where the current section is gonna be select it on scroll, but when i try to get the offsetTop of the elements i get alway 0 for some reason, on the parentElement a get value for offsetTop but in this case does not work for me using the offsetTop of the parentElement because i have many childElements inside with different offsetTop.
Template
<div nxCol="12,12,8" *ngIf="selectedPlan && selectedPlan?.id != quotePlan.id && !loading">
<!-- Limits -->
<h5 class="nx-margin-y-0" translate [id]="LIMITS_AND_PRICING_SECTION_ID" #limitPricing> page.service-detail.available-plan.menu.limit-pricing </h5>
<mat-list class="mat-list-padding-none">
<mat-list-item><strong translate>global.label.limits</strong></mat-list-item>
<mat-divider></mat-divider>
<mp-service-plan-limit-display [limits]="selectedPlan?.limits"></mp-service-plan-limit-display>
</mat-list>
<mat-list class="nx-margin-top-m mat-list-padding-none">
<mat-list-item><strong translate>page.service-detail.pricing</strong></mat-list-item>
<mat-divider></mat-divider>
<mp-service-plan-price-display
[prices]="selectedPlan?.prices"
[planId]="selectedPlan?.id"
[availablePlans]="true"
></mp-service-plan-price-display>
</mat-list>
<!-- /Limits -->
<!-- Documentation -->
<ng-container *ngIf="planSpecDocuments.length > 0">
<h5 class="nx-margin-top-3xl nx-margin-bottom-2xs" translate [id]="DOCUMENTATION_SECTION_ID" #documentation>
page.service-detail.available-plan.menu.documentation
</h5>
<p class="nx-margin-0">Details how to embed the Service into your application.</p>
<mat-list class="mat-list-padding-none mat-file-list">
<ng-container *ngFor="let specDocument of planSpecDocuments">
<mat-list-item>
<ng-container *ngIf="(partnerId$ | async)?.length && !isPreview; else documentSpecDisabledTpl">
<a [href]="specDocument.specDocumentUrl | async" [download]="specDocument.name" class="file-links file-link-active">
<span class="icon-document mpt-icon"></span>{{ specDocument.name }}
</a>
</ng-container>
<ng-template #documentSpecDisabledTpl>
<span class="file-links">
<span class="icon-document mpt-icon"></span>
{{ specDocument.name }}
</span>
</ng-template>
</mat-list-item>
</ng-container>
</mat-list>
</ng-container>
<!-- /Documentation -->
</div>
Component
#ViewChild('limitPricing') limitPricing!: ElementRef;
#ViewChild('documentation') documentation!: ElementRef;
#ViewChild('swaggerSpec') swaggerSpec!: ElementRef;
timer(500).subscribe(() => {
console.dir(this.limitPricing?.nativeElement);
this.limitPricingOffset = this.limitPricing?.nativeElement.offsetTop - 100; // offsetTop here is always zero
this.documentationOffset = this.documentation?.nativeElement.offsetTop - 100;
this.swaggerSpecOffset = this.swaggerSpec?.nativeElement.offsetTop - 100;
});
Declare the element in the constructor, as private _element: ElementRef) { ...}
this._element.nativeElement.getBoundingClientRect().top

Conditional print on html of angular

I am looping through a list of products and then checking if the product Id is already present in an array of products(objects) , then printing the quantity else if the product is not in the object then trying to print 0. Below is the code I have tried till now.
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart" >
<span class="count" *ngIf="cartitem.p_id==item.p_id;">
{{cartitem.qty}}
</span>
</ng-container>
</ion-item>
How to print 0 if item is not in the cartitem in same span.
You can simply do this using ternary operator like below.
<ng-container *ngFor="let cartitem of cart" >
<span class="count">
{{cartitem.p_id==item.p_id ? cartitem.qty : 0 }}
</span>
</ng-container>
Can use *ngIf else condition inside your for loop -
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart">
<span class="count" *ngIf="cartitem.p_id==item.p_id; then content else other_content">
</span>
<ng-template #content>{{cartitem.qty}}</ng-template>
<ng-template #other_content>0</ng-template>
</ng-container>
</ion-item>
Instead of using template logic I would move the logic to the class.
cart and products are obviously available in the class.
Therefore adjust the fetchProducts function in the class to return the products list as needed (with the quantity information) and use a single ngFor loop in the template.
Or add a new function getProductsWithQuantity...
In your class
public getProductsWithQuantity() {
return this.fetchProducts().map(product => {
...product,
quantity: this.getQuantity(product);
});
}
private getQuantity(product) {
const foundCartItem = this.cart.find(cartItem => product.id === cartItem.id);
if (foundCartItem) {
return foundCartItem.qty;
}
return 0;
}
In your template:
<ion-item class="added" *ngFor="let item of getProductsWithQuantity();let key=index;">
<span class="count">
{{item.qty}}
</span>
...

Angular - How to sort table data according to specific column

I have a table with 3 colums. But I want to sort the table data according to first column (Domain) alphabetically. My table html is:
<mat-table #table [dataSource]="tableData">
<ng-container cdkColumnDef="domain">
<mat-header-cell *cdkHeaderCellDef fxFlex="50%">Domain</mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="50%">{{config.domain}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="disable">
<mat-header-cell *cdkHeaderCellDef fxFlex="30%">Disabled</mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="30%">{{config.disabled}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="button">
<mat-header-cell *cdkHeaderCellDef fxFlex="15%"></mat-header-cell>
<mat-cell *cdkCellDef="let config" fxFlex="15%">
<mat-icon (click)="deleteDomain(config)" style="cursor: pointer">delete_forever</mat-icon>
</mat-cell>
</ng-container>
<mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *cdkRowDef="let config; columns: displayedColumns;"></mat-row>
</mat-table>
And my .ts file for this table is consisting following code :
private _domainData = new BehaviorSubject<Domain[]>([]);
#Input()
set domainData(value: Domain[]) {
this._domainData.next(value);
}
displayedColumns = ['domain', 'disable', 'button'];
tableData: Domain[];
Is it possible to achieve this ?
You can achieve this from the TypeScript by sort method when clicked on the particular column.
I don't think you need to write this logic in the back end.
If the intention is to just display the sorted data according to your Domain column. Then, please do at blackened that would be much better.
Hope this helps.
If you are using Angular Material, you can use Sort Header to sort data .
Or atleast you can use the logic they provided for sorting in first example.

Angular 5 is not rendering the component until click or hover anywhere

im having this issue which is breaking my head right now and I cant figured out what is the problem.
I have a form called device-form, which is called from the dashboard using routing. The device form has inside 4 tabs (angular material), and the second one must show a Highchart component, when you select that tab, the container appears but not the chart.... if you wait, the chart will never show up, but if you click in any place the chart appears, also if you hover some item with mouse, or if you resize the screen!!
App-chart-box.component.html:
<mat-card fxFlex="100%" fxLayout="row">
<mat-card-title></mat-card-title>
<mat-card-content>
<mat-tab-group class="form-wizard tab-group">
<mat-tab *ngFor="let chart of charts; let i = index">
<ng-template mat-tab-label>
{{ chart.sensorTypeName }}
</ng-template>
<div class="tab-content">
<vr-chart class="card-img-top" [title]="chart.sensorTypeName" [yTitle]="chart.sensorTypeUnit" type="spline" [series]="chart.series"
[period]="period" [minThreshold]="minThreshold" [maxThreshold]="maxThreshold"></vr-chart>
</div>
</mat-tab>
</mat-tab-group>
</mat-card-content>
<mat-card-actions>
<small class="footer">Last updated: {{ dateUpdated }}</small>
</mat-card-actions>
device-form.component.html:
<mat-tab>
<ng-template mat-tab-label>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<span>Statistics</span>
</div>
</ng-template>
<div fxFlex="100%" class="shipping-address" fxLayout="column">
<mat-form-field class="select-period">
<mat-select placeholder="{{ 'DEVICE_FORM.PERIOD' | translate }}" [(ngModel)]="filterPeriodSelected" (change)="loadDeviceChart()">
<mat-option *ngFor="let period of chartPeriods" [value]="period.value">
{{ period.label | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<!-- <div *ngIf="deviceCharts.length == 0" class="alert bg-primary alert-dismissible fade show" role="alert">
<strong class="ng-tns-c6-44"> {{'MESSAGE.NO_DATA_TO_SHOW' | translate}}</strong>
</div> -->
<vr-chart-box *ngIf="deviceCharts" class="fix-width" [charts]="deviceCharts" [period]="filterPeriodSelected"></vr-chart-box>
</div>
</mat-tab>
As you see the app-chart-box component is rendered, actually we can always see the footer loaded, always, but the body of the chart dont appear until click or hover o whatever.
Update:
Actually Im having the very same issue with a table which is filled with data coming from an API when you change a dropdown up there in the main dashboard page, the table component is always listening to .onCompanyChange.subscribe, read all the data, but the table is not showing until you make click or hover or whatever event... this is the code :
Table component:
export class CompanyHistoryComponent implements OnInit {
#ViewChild('tableInput') tableInput: ElementRef;
#Input() companyId = 0;
private rows: Observable<Array<any>>;
// public rows: any[] = [];
resultsLength: number;
dataSource: ListDataSource<any> | null;
database: ListDatabase<any>;
tableHover = true;
tableStriped = true;
tableCondensed = true;
tableBordered = true;
constructor(
public sensorService: SensorService,
public dashboardService: DashboardService,
private cd: ChangeDetectorRef,
) {
// Selected company changed
this.dashboardService.onCompanyChange.subscribe(
(id: number) => {
this.companyId = id;
this.loadSensorHistory();
cd.detectChanges();
});
}
public loadSensorHistory() {
const sDate: Number = moment().subtract(30, 'day').unix()
const eDate: Number = moment().unix();
this.sensorService.getSensorDataHistory(this.companyId, sDate, eDate, null, null, 1, 10).subscribe(response => {
if (response.statusCode !== 200 || !response.data) {
// this.toastrService.error('MESSAGE.NO_DATA', 'SENSOR_FORM_LIST.TITLE', { positionClass: 'toast-top-right', closeButton: true });
} else {
this.rows = response.data.list;
}
});
}
ngOnInit() {
}
As you see this time I added detectChanges() without any results :(
let me know if you have an idea.
This is the HTML of the Table :
<table class="table" [class.table-hover]="tableHover" [class.table-striped]="tableStriped" [class.table-condensed]="tableCondensed"
[class.table-bordered]="tableBordered">
<thead>
<tr>
<th>Date</th>
<th>Device</th>
<th>Sensor</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of rows" [class.row-failed]="row.failed > 0">
<td>{{ row.data_createdDate | date:'MM/dd/yyyy HH:mm:ss a Z' }}</td>
<td>
{{ row.deviceMAC }}
</td>
<td>
{{ row.sensorNumber }} - {{ row.sensorName }}
</td>
<td>{{ row.value }}</td>
</tr>
</tbody>
</table>
You should call ChangeDetectorRef detectChanges()
It might be an incorrect pipe operator.
I had a similar issue with Angular 11 and mat-table. The rows wouldn't show up until I hovered over them. My issue was that I was using an invalid pipe operator on one of the columns. I was using a decimal pipe on a string column. Once I corrected that it works perfectly.

Categories

Resources