I would like to help me with updating records in a dynamic table worked with MatTable.
In my component get:
getComponentsFactualGeneral(pil: number){
this.diagnosticoService.readPilarParamFormId(pil).pipe().subscribe(pilar=>{
this.facgeneral = [];
(pilar as Pilari[]).forEach( getpilar => {
this.diagnosticoService.readComponentsPilarId(getpilar.idPilar).subscribe( comp=>{
getpilar.components = comp;
});
this.facgeneral.push(getpilar);
});
});
}
This generate the follow:
The html have:
<mat-tab>
<ng-template mat-tab-label>
<span (click)="getComponentsFormaGeneral(2)">Formal general</span>
</ng-template>
<mat-accordion class="example-headers-align" multi>
<mat-expansion-panel *ngFor="let item of fgeneral">
<mat-expansion-panel-header>
<mat-panel-title> {{ item.descripcion }} </mat-panel-title>
</mat-expansion-panel-header>
<div class="table-responsive">
<table mat-table [dataSource]="item.components" class="mat-elevation-z8"> <!-- here generate datasource -->
<ng-container matColumnDef="nombreestandar">
<th mat-header-cell *matHeaderCellDef> Estandar </th>
<td mat-cell *matCellDef="let element"> {{element.nombreestandar}} </td>
</ng-container>
<ng-container matColumnDef="nombrecomponente">
<th mat-header-cell *matHeaderCellDef> Componente </th>
<td mat-cell *matCellDef="let element"> {{element.nombrecomponente}} </td>
</ng-container>
<ng-container matColumnDef="evidencia">
<th mat-header-cell *matHeaderCellDef> Evidencia </th>
<td mat-cell *matCellDef="let element"> {{ element.evidencia }}
</td>
</ng-container>
<ng-container matColumnDef="conclusionCumple">
<th mat-header-cell *matHeaderCellDef> Cumplimiento </th>
<td mat-cell *matCellDef="let element"> {{ element.conclusionCumple }}
<ng-template #elseBlock>
No cumple
</ng-template>
</td>
</ng-container>
<ng-container matColumnDef="comentariosCc">
<th mat-header-cell *matHeaderCellDef> Comentario </th>
<td mat-cell *matCellDef="let element"> {{ element.comentariosCc }}
</td>
</ng-container>
<ng-container matColumnDef="comentariosComite">
<th mat-header-cell *matHeaderCellDef> Comentarios Comité </th>
<td mat-cell *matCellDef="let element"> {{ element.comentariosComite }}
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Acciones </th>
<td mat-cell *matCellDef="let e; let i=index;">
<button mat-icon-button color="primary" (click)="openDialog(e.idRespuestamacro,e.idEstandar,e.idFormulario,e.idInstitucion,e.idPilar,e.paramComponente)">
<mat-icon aria-label="Edit">edit</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-expansion-panel>
</mat-accordion>
</mat-tab>
The generate datasource from components [dataSource]="item.components"
Now I need to update a row after edit, but how can I do it if datasource is generated from "item.components".
Thank you
For the dynamic table updates, definitely use --> RxJS
Step 1 -- In HTML Use an async pipe
Step 2 -- change fgeneral to fgeneral$ observable list, it will auto update from the observable.
Step 3 -- Make sure you import rxjs libraries
import { Component } from '#angular/core'
import { Observable } from 'rxjs'
Your HTML
<div *ngFor='let item of fgeneral$ | async' ... id="line_{{i}}" class="new-line glow">
// put your row template here...
</div>
In Your Component
// this Function will return an observable array. assign it to what you want..
// this is to give you an idea... a quick edit... will not compile..
public getComponentsFactualGeneral(): Observable<Fac[]> {
return this.http.get(this.baseUrl + '/xyz')
.pipe(
catchError(this.handleError('getFacs', []))
)
.map(fac => {
if(Array.isArray(fac )) {
return fac .map((item) => new Facs(item));
} else {
return [new Facs(fac )];
}
});
}
This ref should help.. and this
Related
I have a table where a column is a text input.
When the user edits the text both a save and cancel button became enabled.
The save button should just send the new value to the server. I can do that one no problem.
But the cancel button I can't figure out how to change the input back. Because with both model or a child element how do I know which element of the table I'm writing in?
The template part:
<table mat-table [dataSource]="gsServersDataSource" class="mat-elevation-z8">
<tr mat-header-row *matHeaderRowDef="gsServersHeaders"></tr>
<tr mat-row *matRowDef="let row; columns: gsServersHeaders;"></tr>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef > Name </th>
<td mat-cell *matCellDef="let element" > {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by value"> Value </th>
<td mat-cell *matCellDef="let element">
<input id="valueInput" type="text" value="{{element.value}}" (keyup)="onChangeValue()">
</td>
</ng-container>
<ng-container matColumnDef="modify">
<th mat-header-cell *matHeaderCellDef> Modify </th>
<td mat-cell *matCellDef="let element">
<button id="saveChanges" mat-mini-fab color="primary" (click)="onClickSave()" [disabled]="disabled">
<mat-icon>✓</mat-icon>
</button>
<button id="cancelChanges" mat-mini-fab color="primary" (click)="onClickCancel(element)" [disabled]="disabled">
<mat-icon>X</mat-icon>
</button>
</td>
</ng-container>
</table>
The component part:
gsServersDataSource = [{name: 'name1', value: 'value1'}];
gsServersHeaders: string[] = ['name', 'value', 'modify'];
disabled=true;
onChangeValue(){
this.disabled=false;
}
onClickSave(element: InstanceDataPoint){
//service call with new value
this.disabled=true;
}
onClickCancel(element: InstanceDataPoint){
//Put original back : How to??
this.disabled=true;
}
}
I created another value for each line that contains the temporary value the user inputted.
When the user wants to save it, it will be posted and on success saved as the original value.
When the user wants to cancel the changes. The temporary value will be reset to the original value.
On the template I'm now using the newValue as the value of the text input.
And I'm passing to the keyup hook the inputted value
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header sortActionDescription="Sort by value"> Value </th>
<td mat-cell *matCellDef="let element">
<input id="valueInput" type="text" value="{{element.newValue}}" (keyup)="onChangeValue(element,$event.target.value)">
</td>
</ng-container>
On the component, I'm now saving the inputted value to the newValue on changes to the text input.
On clicking save I'm assigning the newValue to the originalValue if the post is successful.
And on clicking cancel I'm putting the newValue back to the originalValue.
onChangeValue(element: InstanceDataPoint, newValue: string){
element.disabled = false;
element.newValue = newValue;
}
onClickSave(element: InstanceDataPoint){
this.gsInstancesService.postModifiedValue(this.selectedEnvironment,
{ "param-name": element.name, "param-val": element.newValue, "server-id": element.server, "language": element.language}).
subscribe({complete: ()=>element.value=element.newValue});
element.disabled=true;
}
onClickCancel(element: InstanceDataPoint){
element.newValue = element.value;
element.disabled = true;
}
I have build a table in Angular Material with a general filter (I have followed the official documentation for that). For the purpose of my project I would like to have different filter for each column of my table. For example a filter for the column "name" and another filter for the column "amount". How can I achieve this?
html
<mat-form-field appearance="standard" color="accent">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Search" #input>
</mat-form-field>
<table mat-table [dataSource]="expense" class="mat-elevation-z8">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef> Amount </th>
<td mat-cell *matCellDef="let element"> {{element.amount | currency:'CHF '}} </td>
</ng-container>
[...]
</table>
typescript
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
im trying to show a list of products, and it does, but the problem is it freeze for 6 or 8 seconds, tha size of the register is 2338, im using entity framework to obtain the register, some idea to solve or optimize
this is the method to get the list from the other class and there i obtain from the entity framework
getProveedor(){
this.apiproveedor.getProveedor().subscribe(response=>{
console.log(response.data);
if(response.exito==1){
this.lst=response.data;
this.resultsLength=this.lst.length;
this.dataSource=response.data;
}
});
getProveedor():Observable<Response>{
return this._http.get<Response>(this.url);
}
this is the html, im using a mat table
<!--
-->
<div>
<mat-toolbar >
<span >Pharmacy Lion</span>
<img src="./assets/img/2.png" class="tama">
</mat-toolbar>
<div>
<a mat-raised-button color="primary" (click)="openAdd()">Nuevo Producto</a>
</div>
<mat-form-field appearance="standard">
<mat-label>Filter</mat-label>
<input matInput placeholder="Buscar Nombre" #input (keyup)="applyFilter($event)">
</mat-form-field>
<table mat-table [dataSource]="lst" class="table"
matSort matSortActive="created" matSortDisableClear matSortDirection="desc">
<ng-container matColumnDef ="IdProducto" class="header-align-right"
mat-sort-header disableClear>
<th mat-header-cell *matHeaderCellDef mat-sort-header >#</th>
<td mat-cell *matCellDef="let element">{{element.idProducto}}</td>
</ng-container>
<ng-container matColumnDef ="Nombre" >
<th mat-header-cell *matHeaderCellDef mat-sort-header class="header-align-right" >Nombre Producto</th>
<td mat-cell *matCellDef="let element" class="header-align-right">{{element.nombre}}</td>
</ng-container>
<ng-container matColumnDef ="Cantidad">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="header-align-right"> Cantidad </th>
<td mat-cell *matCellDef="let element" class="header-align-right">{{element.cantidad}}</td>
</ng-container>
<ng-container matColumnDef ="Descripcion">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="header-align-right">Descripcion</th>
<td mat-cell *matCellDef="let element" class="header-align-right">{{element.descripcion}}</td>
</ng-container>
<ng-container matColumnDef ="Precio">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="header-align-right">Precio</th>
<td mat-cell *matCellDef="let element" class="header-align-right">{{element.precio}}</td>
</ng-container>
<ng-container matColumnDef ="Acciones">
<th mat-header-cell *matHeaderCellDef class="header-align-right margencab" >Acciones</th>
<td mat-cell *matCellDef="let element" class="header-align-right ">
<button (click)="Edit(element)" mat-raised-button color="primary" class="margencab">Editar</button>
<button (click)="delete(element)" mat-raised-button color="Basic" class="margencab">Eliminar</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="Columnas"></tr>
<tr mat-row *matRowDef="let row; columns Columnas"></tr>
</table>
</div>
You could try implementing lazy loading of data, which is mentioned in material docs.
You can implementing server side pagination. You need to send page size and page number along with your existing query parameters. In this way it will be more scalable no matter how many data you have cause you are dealing with small chunk of data each request.
you can find a lot of examples out there. With a quick search I found this article one that seems easier to understand
You could also try to implement virtual-scroller provided by material angular CDK (Common Development Kit).
You can find the details here.
I have the following HTML file to show some values:
<h1 mat-dialog-title color="primary">
License Details
</h1>
<mat-dialog-content >
<div style="width:100%;display: flex;flex-direction: column;">
</div>
</mat-dialog-content>
<mat-dialog-content>
<div class="example-container mat-elevation-z8">
<table mat-table [dataSource]="customerList" class="a">
<ng-container matColumnDef="Customer ID" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef class="customtd" style="font-size:15px;"><strong>Customer Id*</strong></th>
<td mat-cell *matCellDef="let element" class="customtd"> {{element.customerId}} </td>
</ng-container>
<ng-container matColumnDef="Hardware Key" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef class="customtd" style="font-size:15px;"><strong>Hardware Key</strong></th>
<td mat-cell *matCellDef="let element" class="customtd"> <textarea rows="2" cols="20" wrap="hard">{{element.hardwareKey}}</textarea> </td>
</ng-container>
<ng-container matColumnDef="Product" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef style="font-size:15px;" class="customtd"><strong>Product</strong></th>
<td mat-cell *matCellDef="let element"> {{element.product}} </td>
</ng-container>
<ng-container matColumnDef="MSAN" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef style="font-size:15px;" class="customtd"><strong>MSAN</strong></th>
<td mat-cell *matCellDef="let element"> {{element.msan}} </td>
</ng-container>
<ng-container matColumnDef="CPE" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef style="font-size:15px;" class="customtd"><strong>CPE</strong></th>
<td mat-cell *matCellDef="let element"> {{element.cpe}} </td>
</ng-container>
<ng-container matColumnDef="Service Connections" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef style="font-size:15px;" class="customtd"><strong>Service Connections</strong></th>
<td mat-cell *matCellDef="let element"> {{element.serviceConnections}} </td>
</ng-container>
<ng-container matColumnDef="License Key" margin-right:10px margin-left:5px>
<th mat-header-cell *matHeaderCellDef style="font-weight: bold;" style="font-size:15px;" class="customtd"><strong>License Key</strong></th>
<td mat-cell *matCellDef="let element"> <textarea rows="2" cols="20" wrap="hard" [readonly]="!editable">{{element.licenseKey}} </textarea></td>
</ng-container>
<ng-container matColumnDef="Actions" margin-right:10px margin-left:10px>
<th mat-header-cell *matHeaderCellDef style="font-weight: bold;" style="font-size:15px;" class="customtd"><strong>Actions</strong></th>
<td mat-cell *matCellDef="let element">
<button type="button" style="margin-left:5px" (click)="deleteLicense(element.id)">Delete</button>
<button type="button" style="margin-left:5px" (click)="openMxkLicenseDetailsDialog()">Update</button>
<button type="button" style="margin-left:5px" (click)="copyLicenseToClipboard(element.licenseKey)" class='btn btn-primary'>Copy License Key</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky:true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-dialog-content>
<br>
<br>
<br>
<strong>* Customer ID might not be present for some products.</strong>
<mat-dialog-actions align="end">
<button mat-button mat-raised-button mat-dialog-close cdkFocusInitial color="warn">Close</button>
</mat-dialog-actions>
This page looks like this:
I want to add a search button on top of this popup after the heading. I want to refine this list based on the Customer ID which is of type String. However, the primary key is ID of type long, not shown. ID is #GeneratedValue of property Auto at the backend. I tried the following code but could not implement it properly: https://stackblitz.com/edit/angular-search-filter?file=app%2Fapp.component.ts
The Component.ts file for this is:
#Component({
selector: 'customer-list-dialog',
templateUrl: 'customer-list-dialog.html',
})
export class CustomerListDialog implements OnInit {
customerList : any;
isupdated = false;
displayedColumns: string[] = ['Customer ID', 'Hardware Key', 'Product', 'MSAN', 'CPE', 'Service Connections', 'License Key', 'Actions'];
constructor(
public dialogRef: MatDialogRef<AddProductDialog>,
private generateLicenseService: GeneratelicenseService,
#Inject(MAT_DIALOG_DATA) public data) {
}
ngOnInit() {
console.log("before the call : "+this.customerList);
if(this.customerList === undefined) {
this.generateLicenseService.getCustomerDetails()
.subscribe((data) => {
this.customerList = data;
//console.log("after the call : "+this.customerList);
});
}
}
And the service.ts portion is:
getCustomerDetails() {
let headers = new HttpHeaders({
'Content-Type': 'application/json'
})
let options = {headers:headers, observer: 'response'};
let result : Observable<Object> = this.http.get(this.url+'/customer/licenses',options);
return result;
}
If I'm understanding your question properly, you just want a simple text filter akin to your provided link?
I would suggest the simplest thing to do would be to change the input data source for your table from customerList to filteredCustomerList.
In your component, after receiving your customer list and saving it as customerList, also save it as another variable filteredCustomerList.
With the addition of your newest search input textbox, for example:
<input type="text" [(ngModel)]="filterText" (change)="onFilterChange()">
You can then change the filteredCustomerList contents - leaving the original customerList as the source of the data from which to filter otherwise untouched in the background. For example:
public onFilterChange(): void {
if (!this.filterText || this.filterText.length === 0) {
this.filteredCustomerList = this.customerList;
return;
}
this.filteredCustomerList = this.customerList.filter(x => x.customerId.toString().includes(this.filterText));
}
I suspect that the filter would look something like that, given your concerns about data types (strings vs numeric types). At the end of the day, numbers have (everything has, frankly) a .toString() method available, so that you can compare the entered filter text vs the customer IDs.
This should have the desired effect of changing the input data source based on the entered filter text.
Edit: (change) event is only fired when focus is removed (clicked off the text box) or you hit enter. Switch to (keyup) if you want filtering as you type.
Quick example of the described mechanism working - StackBlitz
I'm new to Angular Material and have been implementing the MatTable by fetching the data from the Firebase (Real-time Database). For every Row of the MatTable, I need a button to delete the particular data of the row by its $key. The MatTable, fetching of data and the button shows up properly. Just when the button is clicked, it doesn't calls the delete function given in the click event.
Angular 8.2
Angular Material 8.2.3
Firebase 7.14.1
Typescript 3.5.3
HTML code for MatTable
<mat-table [dataSource]="listData" matSort>
<ng-container matColumnDef="key">
<mat-header-cell *matHeaderCellDef >key</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.$key}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentPRN">
<mat-header-cell *matHeaderCellDef >PRN</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentPRN}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentName" >
<mat-header-cell *matHeaderCellDef >Name</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentName}}</mat-cell>
</ng-container>
<ng-container matColumnDef="studentClass">
<mat-header-cell *matHeaderCellDef>Class</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStudentClass}}</mat-cell>
</ng-container>
<ng-container matColumnDef="startDate">
<mat-header-cell *matHeaderCellDef mat-sort-header>Start Date</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStartDate}}</mat-cell>
</ng-container>
<ng-container matColumnDef="endDate">
<mat-header-cell *matHeaderCellDef mat-sort-header>End Date</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveEndDate}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveType">
<mat-header-cell *matHeaderCellDef>Type</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveType}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveDescription">
<mat-header-cell *matHeaderCellDef>Description</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveDescription}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveTeacher">
<mat-header-cell *matHeaderCellDef>Requested to</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveTeacher}}</mat-cell>
</ng-container>
<ng-container matColumnDef="leaveStatus">
<mat-header-cell *matHeaderCellDef>Status</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.leaveStatus}}</mat-cell>
</ng-container>
<ng-container matColumnDef="action">
<mat-header-cell *matHeaderCellDef>Action</mat-header-cell>
<mat-cell *matCellDef="let row">
<button mat-icon-button color="warn" (click)="withdrawLeave(row.$key)">
<mat-icon>delete_outline</mat-icon></button>
</mat-cell>
</ng-container>
<ng-container matColumnDef="loading">
<mat-footer-cell *matFooterCellDef colspan="6">Fetching data...</mat-footer-cell>
</ng-container>
<ng-container matColumnDef="noData">
<mat-footer-cell *matFooterCellDef colspan="6">No data found.</mat-footer-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayColumns"></mat-header-row>
<mat-row *matRowDef="let rows; columns: displayColumns;"></mat-row>
<mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':listData!=null}"></mat-footer-row>
<mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide':!(listData!=null && listData.data.length==0)}"></mat-footer-row>
</mat-table>
<mat-paginator [pageSizeOptions]="[5,10,20,30]" [pageSize]="5" showFirstLastButtons></mat-paginator>
Typescript for button click event
withdrawLeave($key){
if(confirm("Do you want to withdraw the leave request?")){
this.auth.withdrawLeave($key);
}
Auth Service
leaveList : AngularFireList<any>;
getLeaves(){
this.leaveList = this.firebase.list('Leaves');
return this.leaveList.snapshotChanges();
}
withdrawLeave($key: string){
this.leaveList.remove($key);
}
Typescript for fetching data into MatTable
setAppliedLeaves(){
this.auth.getLeaves().subscribe(list => {
let array = list.map(item => {
return {
$key: item.key,
...item.payload.val()
};
});
this.listData = new MatTableDataSource(array);
this.listData.sort = this.sort;
this.listData.paginator = this.paginator;
});
}
I think the problem is the way you are sending the element to the function.
Here is an example of how I implemented a click - delete.
In the html file:
<ng-container matColumnDef="columndelete">
<th mat-header-cell *matHeaderCellDef>Delete</th>
<td mat-cell *matCellDef="let element">
<h5 (click)="delete(element)"><i class="fa fa-trash"></i>
</h5>
</td>
</ng-container>
and in the ts file:
delete(elm: Details) {
//logic
}
Details is the interface, the type of the element.
BTW, you might want to look at this link https://material.angular.io/components/table/overview,
instead of for example
<mat-table ...>
you should use
<table mat-table ...>