NgOnChanges update table when changes is detected causes infinite service call , which I dont have any idea why. Maybe someone can help. Thanks.
I have parent component TableMultiSortComponent and I passed output EventEmitter which is the table data .
The event or the output from EventEmitter is passed to child component which I will use the pagesize , pageindex etc to query as you can see on the dataServiceEvent on the child component.
And then the output of the request is dealsListData which I pass back from child to parent as data to be populated to the table.
It should update table when there is changes that is why I put it on ngOnchanges which is the initTableMultiSort but right now it is updating the table infinitely , it should only update once if there is changes
#the table data that I am passing from parent component to child component , this.dataServiceEvent.emit(this.table); , this is what I emit cause I will be needing the pageindex, size etc.
#HTML CODE - Parent Component
<mat-card *ngIf="table !== undefined">
<mat-table mat-table [dataSource]="table.dataSource" matMultiSort (matSortChange)="table.onSortEvent()">
<ng-container *ngFor="let column of table.columns" [matColumnDef]="column.id">
<mat-header-cell class="table-multi-sort-header" *matHeaderCellDef [mat-multi-sort-header]="column.id">
<div>{{column.name}}</div>
<div class="sub-text">{{getColumnSubtitle(column.id)}}</div>
</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container *ngIf="column.id !== 'action'; then col; else actionCol"></ng-container>
<ng-template #col>
<app-table-multi-sort-cell-default [cellData]="row" [id]="column.id" [subId]="getColumnSubId(column.id)"></app-table-multi-sort-cell-default>
</ng-template>
<ng-template #actionCol>
<app-table-multi-sort-cell-action [rowData]="row" [actions]="getActions(column.id)" (actionClickEvent)="clickTableAction($event,row)"></app-table-multi-sort-cell-action>
</ng-template>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="table.displayedColumns; sticky:true"></mat-header-row>
<mat-row *matRowDef="let item; columns: table.displayedColumns;"></mat-row>
</mat-table>
<mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
</mat-card>
#ts code- parent component
export class TableMultiSortComponent implements OnInit {
#Input() tableOptions:any;
#Input() tableData:any = [];
#Input() isClientSide:boolean = false;
#Input() isLoading: boolean = false;
#Output() tableActionsEvent = new EventEmitter<any>();
#Output() dataServiceEvent = new EventEmitter<any>() ;
#ViewChild(MatMultiSort, { static: false }) sort: MatMultiSort;
tableConfig: any = TABLE_MULTI_SORT_OPTIONS.DEFAULT;
table:TableData<any>;
displayedColumns: any;
constructor() { }
ngOnInit(): void {
this.initTableMultiSort();
}
initTableMultiSort(){
this.tableConfig = {
...this.tableConfig,
...this.tableOptions
}
this.table = new TableData<any>(this.tableConfig.columns,this.tableConfig.sortParams);
this.table.pageSize = this.tableConfig.pageSize;
this.table.pageIndex = this.tableConfig.pageIndex;
this.table.nextObservable.subscribe(() => { this.getData(); });
this.table.sortObservable.subscribe(() => { this.getData(); });
this.table.previousObservable.subscribe(() => { this.getData(); });
this.table.sizeObservable.subscribe(() => { this.getData(); });
setTimeout(()=>{
this.table.dataSource = new MatMultiSortTableDataSource(this.sort, this.isClientSide);
this.getData();
},0);
}
ngOnChanges(changes: SimpleChanges) {
if (changes.tableData && changes.tableData.currentValue){
console.log("changes" , changes)
this.initTableMultiSort()
}
}
getData(){
this.table.totalElements = 1;
this.table.pageIndex = 0;
this.table.pageSize = 10;
this.table.data = this.tableData;
if(this.dataServiceEvent) {
this.dataServiceEvent.emit(this.table);
}
}
#child component HTML code
<app-table-multi-sort (dataServiceEvent)="dataServiceEvent($event)" [tableOptions]="tableOptions" [tableData]="dealsListData" (tableActionsEvent)="tableActions($event)"></app-table-multi-sort>
#child component ts code
export class DealsTransactionComponent implements OnInit {
#Input() transactionId: any = 2;
#Input() transactionName: string = '-';
#ViewChild(TableMultiSortComponent, { static: true }) tableMultiSortComponent: TableMultiSortComponent;
private currentTableConfig: TableData<any>;
dealsListData: any;
tableOptions: any;
#Input() transaction: any;
isLoading: boolean;
private _destroyed$ = new Subject();
totalDeals : number;
accountId: any;
searchInput: string;
table: any;
constructor(
private dialog: MatDialog,
private dealService: DealService,
private notificationService: NotificationService,
private route: Router,
) {}
ngOnInit(): void {
const currentAccountDetails = localStorage.getItem('currAcct') as any;
if (currentAccountDetails) {
this.accountId = JSON.parse(currentAccountDetails).accountId;
}
this.tableOptions = {
columns:[
{id:'name',name:'Deal Name',subId:'type', subtitle:'Deal Type'},
{id:'annualRentProposed',name:'Annual Rent (Proposed)', subId: 'annualRentCurrent', subtitle:'Annual Rent (Proposed)'},
{id:'firmTermRemain',name:'Firm Term Remaining', subId: 'firmTermAdded', subtitle:'(Current)'},
{id:'maxTerm',name:'Max Available Term'},
{id:'cash',name:'Cash Contribution'},
{id:'action', name: 'Actions', actions:[
{icon:'file_copy', name:'Copy', class:'primary-color'},
{icon:'delete', name: 'Delete', class:'mat-error'},
{icon:'forward', name: 'For Approval', class:'primary-color'}
]}
]
}
}
dataServiceEvent(item) {
this.table = item;
if(this.table) {
this._pageEventMyList();
}
}
private _pageEventMyList() {
if (!this.shouldLoadData(this.currentTableConfig, this.table)) {
return;
}
this.currentTableConfig = this.table;
this.searchInput = '';
this.isLoading = true;
this.dealService
.getAllDeals(
this.accountId,
this.transaction.id,
this.table.pageIndex + 1,
this.table.pageSize,
this.searchInput,
this.table.sortParams,
this.table.sortDirs
)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({
error: (err) => this.notificationService.showError(err),
next: (res) => {
this.dealsListData = res.totalItemCount;
this.dealsListData = res.lastItemOnPage;
this.totalDeals = res.items.length;
this.dealsListData = res.items;
console.log("this.dealsListData" , this.dealsListData)
},
complete: noop,
});
}
private shouldLoadData(oldTableConfig: TableData<any>, tableConfig: TableData<any>): boolean {
if (!oldTableConfig) {
return true;
}
return oldTableConfig.pageIndex !== tableConfig.pageIndex
|| oldTableConfig.pageSize !== tableConfig.pageSize
|| oldTableConfig.sortParams !== tableConfig.sortParams
|| JSON.stringify(oldTableConfig.sortParams) !== JSON.stringify(tableConfig.sortParams)
|| JSON.stringify(oldTableConfig.sortDirs) !== JSON.stringify(tableConfig.sortDirs);
}
createDeal() {
this.route.navigateByUrl(`deals/detail/${this.transactionId}~create`, {
state: { data: this.transaction },
});
localStorage.removeItem('breadCrumbsPath');
const breadCrumbsPath = [
{
text: 'My transactions',
link: '/transactions',
},
{
text: this.transactionName,
link: `/transactions/overview/${this.transactionId}`,
},
];
localStorage.setItem('breadCrumbsPath', JSON.stringify(breadCrumbsPath));
}
copyDeal(id: number) {
const data = { id : id }
this.duplicateDeal(data)
}
deleteDeal(id: number) {
this.isLoading = true;
this.dealService.delete(id)
.pipe(finalize(() => { this.isLoading = false;}))
.subscribe({
next: (res) => {
this.dealsListData = this.dealsListData.filter((x) => x.id !== id);
this.notificationService.showSuccess('Deal been removed successfully.');
},
error: (err) => {
this.notificationService.showError('Something went wrong, Try again later.');
this.isLoading = false;
},
complete: () => {
this.isLoading = false;
},
});
}
duplicateDeal(data: any) {
this.isLoading = true;
this.dealService.duplicate(data)
.pipe( finalize(() => { this.isLoading = false;}))
.subscribe({
next: (res) => {
let copyData = {
...this.dealsListData.filter((x) => x.id === data.id),
};
copyData.name = copyData.name + '(copy)';
copyData.id = this.dealsListData[this.dealsListData.length - 1].id + 1;
this.notificationService.showSuccess('Deal was successfully duplicated.' );
},
error: (err) => {
this.notificationService.showError('Something went wrong, Try again later.');
this.isLoading = false;
},
complete: () => {
this.isLoading = false;
},
});
}
approveDeal(data: any) {
this.isLoading = true;
this.dealService
.approve(data)
.pipe(finalize(() => { this.isLoading = false; }))
.subscribe({
next: (res) => {
this.notificationService.showSuccess('Deal was approved');
},
error: (err) => {
this.notificationService.showError('Something went wrong, Try again later.');
this.isLoading = false;
},
complete: () => {
this.isLoading = false;
},
});
}
You are emitting this.table whenever you call getData in the TableMultiSortComponent which happens in ngOnInit for the first time.
This event emission (I suppose) triggers the actual data fetch in the parent component, in the tableActions method (could not see the implementation of this method in the code you included). This method is probably doing something similar to _pageEventMyList that gets data from the API and sets the dealsListData property on the TableMultiSortComponent ([tableData]="dealsListData").
This in turn, triggers your onChange in the TableMultiSortComponent and also passes your if check (the tableData is actually changed). From onChange, you call initTableMultiSort that reinitializes this.table and emits it with this.dataServiceEvent.emit(this.table);. This makes all go into a cycle.
I recommend to implement some extra checks to make sure you are not triggering data reload if the table configuration is the same.
In short, it looks like you use the table for providing you data about the pageIndex, pageSize, sortParams and sortDirs, so I suggest to keep information about the value of these properties when you try to load data again. Compare them, and if something is changed, then fetch data
private currentTableConfig: TableData<any>;
private _pageEventMyList() {
if (!shouldLoadData(currentTableConfig, this.table)) {
return;
}
this.currentTableConfig = this.table;
this.searchInput = '';
this.isLoading = true;
this.dealService
.getAllDeals(
this.accountId,
this.transaction.id,
this.table.pageIndex + 1,
this.table.pageSize,
this.searchInput,
this.table.sortParams,
this.table.sortDirs
)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({
error: (err) => this.notificationService.showError(err),
next: (res) => {
this.dealsListData = res.totalItemCount;
this.dealsListData = res.lastItemOnPage;
this.totalDeals = res.items.length;
this.dealsListData = res.items;
},
complete: noop,
});
}
and the new shouldLoadData method performs the checks:
private shouldLoadData(oldTableConfig: TableData<any>, tableConfig: TableData<any>): boolean {
if (!oldTableConfig) {
return true;
}
return oldTableConfig.pageIndex !== tableConfig.pageIndex
|| oldTableConfig.pageSize !== tableConfig.pageSize
|| JSON.stringify(oldTableConfig.sortParams) !== JSON.stringify(tableConfig.sortParams)
|| JSON.stringify(oldTableConfig.sortDirs) !== JSON.stringify(tableConfig.sortDirs);
}
Disclaimer for using JSON.stringify:
This works, but it is not optimal. If you have another third party library installed, like lodash, you can go for _.isEqual instead (or something similar, that will compare the array contents for you).
Related
I have a button on the parent lwc. When called, it will call a method on the child lwc to perform data update via apex method. Once done, it calls refreshApex to refresh the data on the lightning datatable. RefreshApex will not trigger for some reason.
Now, if I use the child's save button to save the changes, refreshApex will trigger and data will update without any issues.
Appreciate your help!!!
enter image description here
PARENT COMPONENT
</div>
<footer class="slds-modal__footer">
<lightning-button label="Save" variant="brand" onclick={saveModal} class="slds-m-left_x-small"></lightning-button>
<lightning-button label="Cancel" variant="neutral" onclick={closeModal} class="slds-m-left_x-small"></lightning-button>
</footer>
PARENT JS
saveModal() {
//firing a child method
this.template.querySelector("c-reuse-license-key-table").testHandleAction();
}
CHILD COMPONENT
<template if:true={quotelinelist}>
<div class="slds-grid_align-end" style="height: 500px; overflow: auto;">
<lightning-datatable key-field="Id"
data={quotelinelist}
columns={columns}
onsave= {testHandleAction}
oncellchange= {handleRowAction}
draft-values={fldsItemValues}
hide-checkbox-column="true"> <!--suppress-bottom-bar="true"-->
</lightning-datatable>
</div>
</template>
CHILD JS
#wire(getQuoteLinesList,{quoteId: '$parentRecordId', actionType: '$actionTypeForWire'})
cons(result) {
console.log('check result 1 ', result)
this.wiredDataResult = result;
if(result.error) {
console.log('inside wire error')
//this.quotelineList = undefined;
}
else {
console.log('inside else error')
this.quotelinelist = result.data;
}
}
handleRowAction(event) {
lKeyDraftList.push(event.detail.draftValues);
}
#api async testHandleAction() {
let strOriginalKeyValues = JSON.stringify(qlInList);
let strlKeyDraftList = JSON.stringify(lKeyDraftList);
let strDraftValue = [];
lKeyDraftList.forEach(function(c){
console.log('check c', c);
c.forEach(function(c2){
console.log('check c2', c2);
strDraftValue.push(c2);
});
});
await updateQuoteLines({IdToObjectForDraftValues : JSON.stringify(strDraftValue)}) //, IdToObjectForOriginalValues: strOriginalKeyValues
.then(result => {
const toast = new ShowToastEvent({
title: 'Success',
message: 'Records Updated Successfully!!',
variant: 'success'
});
this.dispatchEvent(toast);
this.actionTypeForWire = 'update';
return refreshApex(this.wiredDataResult).then(() => {
console.log('after refresh apex')
this.fldsItemValues = [];
});
})
.catch(error => {
console.log('error');
const toast = new ShowToastEvent({
title: 'Error',
message: 'An Error Occurred!!' + error.message,
variant: 'error'
});
this.dispatchEvent(toast);
}).finally(() => {
console.log('inside final', this.fldsItemValues);
});
}
APEX Controller
#AuraEnabled(cacheable=true)
public static List<SBQQ__QuoteLine__c> getQuoteLinesList(Id quoteId, String actionType) {
List<SBQQ__QuoteLine__c> qLineList = new List<SBQQ__QuoteLine__c>();
if(quoteId != null){
qLineList = [SELECT Id,Name,SBQQ__ProductName__c,SBQQ__Quantity__c,Reused_License_Key__c
FROM SBQQ__QuoteLine__c
WHERE SBQQ__RequiredBy__c != NULL
AND SBQQ__Quote__c = :quoteId
ORDER BY SBQQ__ProductName__c];
}
Boolean callLPUtility = true;
for(SBQQ__QuoteLine__c ql : qLineList) {
if(ql.Reused_License_Key__c != null) {
callLPUtility = false;
break;
}
}
if(callLPUtility == true && actionType == 'begin') {
LicenseProductUtility.toMapLicenseKeyForRenewal(qLineList, getSubscriptionsList(quoteId));
}
return qLineList;
}
#AuraEnabled
public static void updateQuoteLines(String IdToObjectForDraftValues) { //String IdToObjectForOriginalValues
List<Object> items = (List<Object>) JSON.deserializeUntyped(IdToObjectForDraftValues);
List<SBQQ__QuoteLine__c> qlList = new List<SBQQ__QuoteLine__c>();
List<Map<String, Object>> theJsonMapList = new List<Map<String, Object>>();
for(Object itemObj : items) {
theJsonMapList.add((Map<String, Object>) itemObj);
}
for(Object o : theJsonMapList){
SBQQ__QuoteLine__c q = new SBQQ__QuoteLine__c();
q.Id = ((Map<String, Object>) o).get('Id').toString();
q.Reused_License_Key__c = ((Map<String, Object>) o).get('Reused_License_Key__c').toString();
qlList.add(q);
}
Savepoint sp = Database.setSavepoint();
if(!qlList.isEmpty()){
try {
update qlList;
} catch (Exception e) {
Database.rollback(sp);
System.debug('An exception occurred updateQuoteLines: ' + e.getMessage());
}
}
}
I have angular 8 application.
And I have two components, like child - parent relationship. So I remove the item from the child, but then the item is still visible in the parent(list of items). Only after page refresh the item is gone from the list.
So I have this service:
export class ItemListService {
_updateItemChanged = new Subject<any>();
_removeItemChanged = new BehaviorSubject<any>([]);
constructor() {}
}
and this is item.ts - child:
openRemoveDialog() {
const dialogRef = this.dialog.open(ItemRemoveDialogComponent, {
width: '500px',
height: '500px',
data: {
dossierId: this.dossier.id,
item: this.item,
attachments: this.item.attachments
}
});
this.itemListService._removeItemChanged.next(this.item.title);
dialogRef.afterClosed().subscribe(result => {
if (result === true) {
this.router.navigate(['/dossier', this.dossier.id]);
}
});
}
and this is the view.ts(item list) - parent: so in this component the refresh has to be made
ngOnInit(): void {
this.show = !this.router.url.includes('/item/');
this.itemlistService._updateItemChanged.subscribe(data => {
const index = this.dossierItems.findIndex(a => a.id === data.id);
this.dossierItems[index] = data;
});
this.itemlistService._removeItemChanged.subscribe(data => {
// this.dossierItems.pop(); What I have to fill in here?
});
So what I have to change?
Thank you
and this is the remove function:
remove() {
this.dossierItemService.deleteDossierItem(this.data.dossierId, this.data.item.id)
.subscribe(() => {
this.dialogRef.close(true);
}, (error) => {
const processedErrors = this.errorProcessor.process(error);
this.globalErrors = processedErrors.getGlobalValidationErrors();
});
}
I have it now like this:
remove() {
this.dossierItemService.deleteDossierItem(this.data.dossierId, this.data.item.id)
.subscribe(() => {
this.dialogRef.close(true);
this.itemListService._removeItemChanged.next(true);
}, (error) => {
const processedErrors = this.errorProcessor.process(error);
this.globalErrors = processedErrors.getGlobalValidationErrors();
});
}
and in the view.ts, like ths:
ngOnInit(): void {
this.itemlistService._removeItemChanged.subscribe(update => update === true ? this.dossierItems : '');
}
but still the list will not be refreshed
You need to create a new reference to your array for Angular to update the screen like this
this.itemlistService._removeItemChanged.subscribe(data => {
// this.dossierItems.pop(); What I have to fill in here?
this.dossierItems = this.dossierItems.filter(e => e.title !== data);
});
Current config (cannot update it to latest):
"#angular/cli": "^7.3.9",
"primeng": "7.0.5",
I have a PrimeNG p-table that has lazy loaded data with pagination.
There is an issue open for it on PrimeNG GitHub too - https://github.com/primefaces/primeng/issues/8139
Stackblitz link is already attached in that issue so didn't create a new one.
Scenario:
One 1st page, some rows are selected via checkbox selection.
On 2nd page, Select All checkbox from the header is selected and all rows on 2nd page is auto-selected.
Now when navigated to the first page, the selections from here are reset. But the Select All checkbox in the header is still checked.
Would like to know if anyone has a workaround for this issue?
Any help is appreciated.
Edit:
Solution found in another similar GitHub issue: https://github.com/primefaces/primeng/issues/6482
Solution:
https://github.com/primefaces/primeng/issues/6482#issuecomment-456644912
Can someone help with the implementation of the override in an Angular 7/8 application. Not able to understand as how to get the TableHeaderCheckbox reference and override the prototype.
Well, the solution to the problem is still not added to the PrimeNG repo and so even the latest package does not have it solved.
For time being, use the solution mentioned in the question under Edit
To answer the question that I have asked under the Edit, check below:
// In some service file:
import { Table, TableHeaderCheckbox } from 'primeng/table';
import { ObjectUtils } from 'primeng/components/utils/objectutils';
import { uniq, each, intersection, map, remove } from 'lodash';
#Injectable()
export class BulkSelectAllPagesService {
overridePrimeNGTableMethods() {
TableHeaderCheckbox.prototype.updateCheckedState = function () {
const currentRows = map(this.dt.value, this.dt.dataKey);
const selectedRows = map(this.dt.selection, this.dt.dataKey);
this.rowsPerPageValue = this.dt.rows;
const commonRows = intersection(currentRows, selectedRows);
return commonRows.length === currentRows.length;
};
Table.prototype.toggleRowsWithCheckbox = function (event, check) {
let _selection;
if (!check) {
_selection = this.value.slice();
each(_selection, (row) => {
const match = {}; match[this.dataKey] = row[this.dataKey];
remove(this._selection, match);
});
} else {
_selection = check ? this.filteredValue ? this.filteredValue.slice() : this.value.slice() : [];
each(this._selection, (row) => {
const match = {}; match[this.dataKey] = row[this.dataKey];
remove(_selection, match);
});
this._selection = this._selection.concat(_selection);
}
this.preventSelectionSetterPropagation = true;
this.updateSelectionKeys();
this.selectionChange.emit(this._selection);
this.tableService.onSelectionChange();
this.onHeaderCheckboxToggle.emit({
originalEvent: event,
affectedRows: _selection,
checked: check
});
};
}
// In app.component.ts
import { Component, OnInit } from '#angular/core';
import { BulkSelectAllPagesService } from 'PATH_TO_THE_FILE/bulk-select-all-pages.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
constructor(
private bulkSelectAllPagesService: BulkSelectAllPagesService) {
}
ngOnInit() {
this.bulkSelectAllPagesService.overridePrimeNGTableMethods();
}
}
Ofcourse need to include the service file in the providers[] in the app.module.ts
Will create a stackblitz and add later.
Improved version to handle rowspan grouped data:
overridePrimeNGTableMethods() {
TableHeaderCheckbox.prototype.updateCheckedState = function () {
const currentRows = map(this.dt.value, this.dt.dataKey);
const uniqueCurrentRows = uniq(currentRows);
const selectedRows = map(this.dt.selection, this.dt.dataKey);
this.rowsPerPageValue = this.dt.rows;
const commonRows = intersection(currentRows, selectedRows);
if (currentRows.length) {
return commonRows.length === uniqueCurrentRows.length;
} else {
return false;
}
};
Table.prototype.toggleRowWithCheckbox = function (event, rowData) {
const findIndexesInSelection = (selection: any = [], data: any = {}, dataKey: any) => {
const indexes = [];
if (selection && selection.length) {
selection.forEach((sel: any, i: number) => {
if (data[dataKey] === sel[dataKey]) {
indexes.push(i);
}
});
}
return indexes;
};
this.selection = this.selection || [];
const selected = this.isSelected(rowData);
const dataKeyValue = this.dataKey ? String(ObjectUtils.resolveFieldData(rowData, this.dataKey)) : null;
this.preventSelectionSetterPropagation = true;
if (selected) {
const selectionIndexes = findIndexesInSelection(this.selection, rowData, this.dataKey);
const selectedItems = this.selection.filter((val: any) => {
return val[this.dataKey] === rowData[this.dataKey];
});
this._selection = this.selection.filter((val: any, i: number) => {
return selectionIndexes.indexOf(i) === -1;
});
this.selectionChange.emit(this.selection);
selectedItems.forEach((selectedItem: any, index: number) => {
this.onRowUnselect.emit({ originalEvent: event.originalEvent, index: event.rowIndex + index, data: selectedItem, type: 'checkbox' });
});
delete this.selectionKeys[rowData[this.dataKey]];
} else {
let rows = [rowData];
if (dataKeyValue) {
rows = this.value.filter(val => {
return (val[this.dataKey]).toString() === dataKeyValue;
});
}
this._selection = this.selection ? this.selection.concat(rows) : rows;
this.selectionChange.emit(this.selection);
this.onRowSelect.emit({ originalEvent: event.originalEvent, index: event.rowIndex, data: rowData, type: 'checkbox' });
if (dataKeyValue) {
this.selectionKeys[dataKeyValue] = 1;
}
}
this.tableService.onSelectionChange();
if (this.isStateful()) {
this.saveState();
}
};
Table.prototype.toggleRowsWithCheckbox = function (event, check) {
let _selection;
if (!check) {
_selection = this.value.slice();
each(_selection, (row) => {
const match = {}; match[this.dataKey] = row[this.dataKey];
remove(this._selection, match);
});
} else {
_selection = check ? this.filteredValue ? this.filteredValue.slice() : this.value.slice() : [];
each(this._selection, (row) => {
const match = {}; match[this.dataKey] = row[this.dataKey];
remove(_selection, match);
});
this._selection = this._selection.concat(_selection);
}
this.preventSelectionSetterPropagation = true;
this.updateSelectionKeys();
this.selectionChange.emit(this._selection);
this.tableService.onSelectionChange();
this.onHeaderCheckboxToggle.emit({
originalEvent: event,
affectedRows: _selection,
checked: check
});
};
}
i want to bind the json file to a smart table. How to use the loop function for the iteration.. please help
It only shows the design of smart table.
didn't binding the data from json
this is the json file
[
{
"year": 2013,
"id": "",
"doctor": "Dr. Smith",
"illness": "Flu",
"apptdate": "3/12/2013",
"details":"Patient had flu for 5 days. No medicines prescribed"
}
]
i used to retrieve data using
#Injectable()
export class SmartTablesService {
constructor(private http: Http) {
}
smartTableData = [];
loadData() {
console.log('loadData');
this.http.get('http://192.168.0.100:8000/medical')
.subscribe((data) => {
setTimeout(() => {
var contactData = [];
$.each(data.json(), function (key, value) {
var tempData = value.source;
contactData.push(tempData);
});
this.smartTableData = contactData;
}, 1000);
});
}
getData(): Promise<any> {
console.log("Promise");
this.loadData();
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(this.smartTableData);
resolve(this.smartTableData);
}, 3000);
});
}
}
constructor(private http: Http) { }
getComments() {
return this.http.get('http://192.168.0.100:8000/article' )
.map((res: Response) => res.json())
.catch((error:any) => Observable.throw(error));
}
}*/
this is the component part
#Component({
selector: 'new',
template: '<ng2-smart-table [settings]="settings" [source]="source"></ng2-smart-table>'
})
export class NewComponent {
query: string = '';
settings = {
noDataMessage: 'Loading...',
columns: {
year: {
title: 'YEAR',
type: 'string'
},
id: {
title: 'ID',
type: 'string'
},
doctor: {
title: 'DOCTOR',
type: 'string'
},
illness: {
title: 'ILLNESS',
type: 'string'
},
apptdate: {
title: 'APPTDATE',
type: 'string'
},
details: {
title: 'DETAILS',
type: 'string'
}
}
};
// data
source: LocalDataSource = new LocalDataSource();
constructor(protected service: SmartTablesService){
this.service.getData().then((data) => {
this.source.load(data);
});
}
}
please anyone anyone know how to bind it ..help
simply change the subscribe part in the service page to
var tempData = value;
so .subscriber looks like
.subscribe((data) => {
setTimeout(() => {
var contactData = [];
$.each(data.json(), function (key, value) {
var tempData = value; contactData.push(tempData);
});
this.smartTableData = contactData;
}, 1000);
});
}
it works..!
My Employee-Management-Component is reloading when it links to itself with route parameters at interaction and this should not happen. Am I having any issues in my code? The <p-dropdown> and <p-datatable> are components from primeNG and do what their name says. EventHandlers and properties should also be easy to understand. If not just ask.
import ...
#Component({
selector: 'employee-management-table',
template: `
<div class="ui-g-12 ui-g-nopad" id="CONTENT">
<nav class="ui-g-12 ui-g-nopad">
<p-dropdown [options]="departments" [(ngModel)]="selectedDeparment" (onChange)="selectDepartment($event)"></p-dropdown>
</nav>
<p-dataTable [value]="employees" [(selection)]="selectedEmployees" (onRowClick)="routeToEmployee($event)">
<p-column [style]="{'width':'38px'}" selectionMode="multiple"></p-column>
<p-column *ngFor="let col of columns" [field]="col.field" [header] = "col.header"></p-column>
</p-dataTable>
<employee-form [employee]="employee"></employee-form>
</div>
`,
styleUrls: [],
directives: [ROUTER_DIRECTIVES, EmployeeFormComponent, Dropdown, DataTable, Column],
})
export class EmployeeManagementTableComponent implements OnInit, OnDestroy{
private employees: Employee[];
private employee: Employee;
private newEmployee: boolean = false;
private selectedEmployees: Employee[];
private departments: SelectItem[] = [];
private selectedDepartment: string;
private columns: any[];
private paramSub: any;
private employeesSub: any;
private departmentSub: any;
constructor(private employeeManagementService: EmployeeManagementService,
private route: ActivatedRoute,
private router: Router,
private ccs: ComponentCommunicatorService,
private logger: Logger) { }
ngOnInit(){
this.columns = [
....
];
this.selectedDepartment = this.ccs.getSelectedDepartment();
this.getDepartments();
this.paramSub = this.route.params.subscribe(
//Success
params => {
if(params['type']){
let type = params['type'];
this.logger.log(type);
if(type === "employee"){
if(params['option']){
let option = params['option'];
this.logger.log(option);
this.doEmployeeOption(option);
}else if(params['id']){
let id = params['id'];
this.logger.log(id);
this.editEmployee(id);
}
}else if(type === "department"){
if(params['option']){
let option = params['option'];
this.logger.log(option);
this.doDepartmentOption(option);
}
}
}
},
//Error
err => this.logger.error(err),
//Complete
() => { }
);
}
ngOnDestroy(){
this.paramSub.unsubscribe();
this.employeesSub.unsubscribe();
this.departmentDub.unsubscribe();
}
doEmployeeOption(option: String){
switch(option){
case 'new':
this.newEmployee = true;
this.employee = new Employee();
break;
case 'delete':
break;
default:
this.logger.log("Default");
break;
}
}
save(){
if(this.newEmployee){
this.employees.push(this.employee);
this.employeeManagementService.insertEmployee(this.employee);
this.newEmployee = false;
}else{
this.employees[this.findSelectedEmployeeIndex()] = this.employee;
}
this.employee = null;
window.history.back();
}
abort(){
this.employee = null;
window.history.back();
}
routeToEmployee(event){
this.logger.log(event.data);
this.employee = event.data;
let link = ['/employee-management/employee', this.findSelectedEmployeeIndex()];
this.router.navigate(link);
}
editEmployee(id: number){
this.logger.log('edit '+id);
for (let employee of this.employees) {
this.logger.log("Edit: "+employee);
}
this.employee = this.employees[id];
this.logger.log('check');
findSelectedEmployeeIndex(): number {
this.logger.log("Method: "+this.employee);
this.logger.log("Method: "+this.employees.indexOf(this.employee));
return this.employees.indexOf(this.employee);
}
selectDepartment(event: any){
this.ccs.setSelectedDepartment(event.value);
this.getEmployees(this.ccs.getSelectedDepartment());
}
getDepartments(){
this.departments.push({label: 'Alle', value: 'all'});
this.departmentSub = this.employeeManagementService.getDepartments().subscribe(
//Sucess
data => {data.forEach((item, index) => {
this.departments.push({label: item, value: index.toString()});
});
},
//Error
err => this.logger.error(err),
//Complete
() => {this.logger.log('done loading');
this.departmentSub.unsubscribe();
this.getEmployees(this.selectedDepartment);}
);
}
getEmployees(department: any){
this.employeesSub = this.employeeManagementService.getEmployees(department).subscribe(
//Sucess
data => {this.employees = data},
//Error
err => this.logger.error(err),
//Complete
() => {this.logger.log('done loading');
/*for (let employee of this.employees) {
this.logger.log("Observable "+employee);
}*/
this.employeesSub.unsubscribe()}
);
}
ROUTES
export const EmployeeManagementRoutes: RouterConfig = [
{
path: 'employee-management',
component: EmployeeManagementComponent,
children: [
{
path: '',
component: EmployeeManagementTableComponent
},
{
path: ':type/:id',
component: EmployeeManagementTableComponent
},
{
path: ':type/:option',
component: EmployeeManagementTableComponent
},
]
}];
Everything gets loaded as wanted but if I click on an employee routeToEmployee routes me to ./employee/:employeeArrayIndex, the page reloads (what it should not) and it crashes in editEmployee where I want to assign the selected employee from the employees array to the employee variable that I can display him.
Error message is 'TypeError: Cannot read property '0' of undefined'. The number is for the array index where the employee should be. So I assume the array is empty after the re-init. Only getDepartments() gets called again but does not call getEmployees() anymore.