Skip to content

Commit 4d637f5

Browse files
author
Juan Gabriel Guzman
committed
feat: #228 Adding angular datatables to customer list component
1 parent dba661e commit 4d637f5

File tree

10 files changed

+5761
-77
lines changed

10 files changed

+5761
-77
lines changed

angular.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,19 @@
2727
"node_modules/datatables.net-dt/css/jquery.dataTables.css",
2828
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
2929
"src/styles.scss",
30-
"node_modules/ngx-toastr/toastr.css"
30+
"node_modules/ngx-toastr/toastr.css",
31+
"node_modules/datatables.net-buttons-dt/css/buttons.dataTables.css"
3132
],
3233
"scripts": [
3334
"node_modules/jquery/dist/jquery.js",
3435
"./node_modules/bootstrap/dist/js/bootstrap.min.js",
35-
"node_modules/datatables.net/js/jquery.dataTables.js"
36+
"node_modules/datatables.net/js/jquery.dataTables.js",
37+
"node_modules/jszip/dist/jszip.js",
38+
"node_modules/datatables.net-buttons/js/dataTables.buttons.js",
39+
"node_modules/datatables.net-buttons/js/buttons.colVis.js",
40+
"node_modules/datatables.net-buttons/js/buttons.flash.js",
41+
"node_modules/datatables.net-buttons/js/buttons.html5.js",
42+
"node_modules/datatables.net-buttons/js/buttons.print.js"
3643
]
3744
},
3845
"configurations": {

karma.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module.exports = function (config) {
2727
functions: 80
2828
}
2929
},
30-
reporters: ['spec'],
30+
reporters: ['spec', 'kjhtml'],
3131
specReporter: {
3232
maxLogLines: 5,
3333
suppressErrorSummary: false,

package-lock.json

Lines changed: 5593 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,17 @@
3636
"ngx-toastr": "^12.0.1",
3737
"rxjs": "~6.5.4",
3838
"tslib": "^1.10.0",
39-
"zone.js": "~0.10.2"
39+
"zone.js": "~0.10.2",
40+
"jszip": "^3.4.0",
41+
"datatables.net-buttons": "^1.6.2",
42+
"datatables.net-buttons-dt": "^1.6.2",
43+
"@types/datatables.net-buttons": "^1.4.3"
4044
},
4145
"devDependencies": {
46+
"angular-datatables": "^9.0.2",
47+
"jquery": "^3.5.1",
48+
"datatables.net": "^1.10.21",
49+
"datatables.net-dt": "^1.10.21",
4250
"@angular-devkit/build-angular": "^0.900.5",
4351
"@angular/cli": "~9.0.4",
4452
"@angular/compiler-cli": "~9.0.3",

src/app/modules/customer-management/components/customer-info/components/customer-list/customer-list.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<thead class="thead-orange">
33
<tr class="d-flex">
44
<th class="col-9">Name</th>
5-
<th class="col-3 text-center"></th>
5+
<th class="col-3 text-center">Options</th>
66
</tr>
77
</thead>
88
<tbody>
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
@import '../../../../../../../styles/colors.scss';
Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,65 @@
1-
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2-
import { MockStore, provideMockStore } from '@ngrx/store/testing';
3-
4-
import { NgxPaginationModule } from 'ngx-pagination';
5-
import { CustomerListComponent } from './customer-list.component';
6-
import { allCustomers } from './../../../../store/customer-management.selectors';
7-
import { CustomerState, SetCustomerToEdit, DeleteCustomer } from 'src/app/modules/customer-management/store';
1+
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
2+
import {MockStore, provideMockStore} from '@ngrx/store/testing';
3+
4+
import {NgxPaginationModule} from 'ngx-pagination';
5+
import {CustomerListComponent} from './customer-list.component';
6+
import {allCustomers} from './../../../../store/customer-management.selectors';
7+
import {
8+
CustomerState,
9+
SetCustomerToEdit,
10+
DeleteCustomer,
11+
LoadCustomers,
12+
CustomerManagementActionTypes
13+
} from 'src/app/modules/customer-management/store';
14+
import {DataTablesModule} from 'angular-datatables';
15+
import {ActionsSubject} from '@ngrx/store';
816

917
describe('CustomerTableListComponent', () => {
1018
let component: CustomerListComponent;
1119
let fixture: ComponentFixture<CustomerListComponent>;
1220
let store: MockStore<CustomerState>;
13-
let mockCustomerSelector;
21+
const actionSub: ActionsSubject = new ActionsSubject();
1422

1523
const state = {
16-
data: [{ tenant_id: 'id', name: 'name', description: 'description' }],
24+
data: [{tenant_id: 'id', name: 'name', description: 'description'}],
1725
isLoading: false,
1826
message: '',
1927
customerIdToEdit: '',
2028
customerId: ''
2129
};
2230

2331

24-
2532
beforeEach(async(() => {
2633
TestBed.configureTestingModule({
27-
imports: [NgxPaginationModule],
34+
imports: [NgxPaginationModule, DataTablesModule],
2835
declarations: [CustomerListComponent],
2936
providers: [
30-
provideMockStore({ initialState: state })
37+
provideMockStore({initialState: state}),
38+
{provide: ActionsSubject, useValue: actionSub}
3139
],
3240
}).compileComponents();
3341
}));
3442

3543
beforeEach(() => {
3644
fixture = TestBed.createComponent(CustomerListComponent);
3745
component = fixture.componentInstance;
38-
fixture.detectChanges();
3946

4047
store = TestBed.inject(MockStore);
4148
store.setState(state);
42-
mockCustomerSelector = store.overrideSelector(allCustomers, state.data);
49+
fixture.detectChanges();
50+
4351
});
4452

4553
it('component should be created', () => {
4654
expect(component).toBeTruthy();
4755
});
4856

49-
it('onNgInit customers are loaded from store executing an action', () => {
57+
it('when the component is initialized the load customer action is triggered', () => {
5058
spyOn(store, 'dispatch');
5159

5260
component.ngOnInit();
5361

54-
expect(store.dispatch).toHaveBeenCalled();
55-
expect(component.customers).toEqual(state.data);
62+
expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
5663
});
5764

5865
it('onClick edit, dispatch SetCustomerToEdit and enable customer form', () => {
@@ -72,7 +79,53 @@ describe('CustomerTableListComponent', () => {
7279
expect(store.dispatch).toHaveBeenCalledWith(new DeleteCustomer('1'));
7380
});
7481

82+
const params = [
83+
{actionName: 'delete', actionType: CustomerManagementActionTypes.DELETE_CUSTOMER_SUCCESS},
84+
{actionName: 'update', actionType: CustomerManagementActionTypes.UPDATE_CUSTOMER_SUCCESS},
85+
{actionName: 'create', actionType: CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS}
86+
];
87+
88+
params.map(param =>
89+
it(`on success ${param.actionName} customer, the load all customer action should be triggered`, () => {
90+
const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
91+
const action = {
92+
type: param.actionType
93+
};
94+
spyOn(store, 'dispatch');
95+
96+
actionSubject.next(action);
97+
98+
expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
99+
}));
100+
101+
params.map(param =>
102+
it(`on success ${param.actionName} customer, the customer form should be disabled`, () => {
103+
const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
104+
const action = {
105+
type: param.actionType
106+
};
107+
actionSubject.next(action);
108+
109+
expect(component.showCustomerForm).toBe(false);
110+
}));
111+
112+
// TODO Make this test work. This is having problems with jquery integration
113+
// it('on success load customers, the customer list should be populated', () => {
114+
// const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
115+
// const action = {
116+
// type: CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS,
117+
// payload: state.data
118+
// };
119+
//
120+
// actionSubject.next(action);
121+
//
122+
// expect(component.customers).toEqual(state.data);
123+
// });
124+
75125
afterEach(() => {
126+
component.dtTrigger.unsubscribe();
127+
component.changeCustomerSubscription.unsubscribe();
128+
component.loadCustomersSubscription.unsubscribe();
76129
fixture.destroy();
77130
});
78131
});
Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,71 @@
1-
import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, AfterViewInit } from '@angular/core';
2-
import { Store, select } from '@ngrx/store';
3-
import { DataTableDirective } from 'angular-datatables';
1+
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild} from '@angular/core';
2+
import {ActionsSubject, Store} from '@ngrx/store';
43

5-
import { Subscription, Subject } from 'rxjs';
6-
import { allCustomers } from './../../../../store/customer-management.selectors';
7-
import { LoadCustomers, DeleteCustomer, SetCustomerToEdit } from './../../../../store/customer-management.actions';
8-
import { Customer } from './../../../../../shared/models/customer.model';
9-
import { ITEMS_PER_PAGE } from 'src/environments/environment';
10-
import {ToastrService} from 'ngx-toastr';
4+
import {Subject, Subscription} from 'rxjs';
5+
import {
6+
CustomerManagementActionTypes,
7+
DeleteCustomer,
8+
LoadCustomers,
9+
SetCustomerToEdit
10+
} from './../../../../store/customer-management.actions';
11+
import {Customer} from './../../../../../shared/models/customer.model';
12+
import {filter} from 'rxjs/operators';
13+
import {DataTableDirective} from 'angular-datatables';
1114

1215
@Component({
1316
selector: 'app-customer-list',
1417
templateUrl: './customer-list.component.html',
1518
styleUrls: ['./customer-list.component.scss'],
1619
})
17-
export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
18-
initPage1 = 1;
19-
itemsPerPage = ITEMS_PER_PAGE;
20+
export class CustomerListComponent implements OnInit, OnDestroy {
21+
2022
@Input() showCustomerForm: boolean;
2123
@Output() changeValueShowCustomerForm = new EventEmitter<boolean>();
22-
24+
@Input()
2325
customers: Customer[] = [];
24-
customerSubscription: Subscription;
25-
dtOptions: DataTables.Settings = {};
26+
dtOptions: any = {};
2627
dtTrigger: Subject<any> = new Subject();
2728
@ViewChild(DataTableDirective, {static: false})
2829
dtElement: DataTableDirective;
2930
isDtInitialized = false;
31+
loadCustomersSubscription: Subscription;
32+
changeCustomerSubscription: Subscription;
3033

31-
constructor(private store: Store<Customer>, private toastrService: ToastrService) {
32-
34+
constructor(private store: Store<Customer>, private actionsSubject$: ActionsSubject) {
3335
}
3436

3537
ngOnInit(): void {
3638
this.dtOptions = {
37-
scrollY: '250px',
38-
paging: false,
39+
scrollY: '290px',
40+
paging: false
3941
};
40-
41-
this.store.dispatch(new LoadCustomers());
42-
const customers$ = this.store.pipe(select(allCustomers));
43-
this.customerSubscription = customers$.subscribe((response) => {
44-
this.customers = response ? response : [];
45-
this.rerender();
42+
this.loadCustomersSubscription = this.actionsSubject$.pipe(
43+
filter((action: any) => (
44+
action.type === CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS
45+
)
46+
)
47+
).subscribe((action) => {
48+
this.customers = action.payload;
49+
this.rerenderDataTable();
4650
});
47-
}
4851

49-
ngAfterViewInit(): void {
50-
this.dtTrigger.next();
52+
this.changeCustomerSubscription = this.actionsSubject$.pipe(
53+
filter((action: any) => (
54+
action.type === CustomerManagementActionTypes.DELETE_CUSTOMER_SUCCESS ||
55+
action.type === CustomerManagementActionTypes.UPDATE_CUSTOMER_SUCCESS ||
56+
action.type === CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS
57+
)
58+
)
59+
).subscribe((action) => {
60+
this.store.dispatch(new LoadCustomers());
61+
this.showCustomerForm = false;
62+
});
63+
this.store.dispatch(new LoadCustomers());
5164
}
5265

5366
ngOnDestroy() {
54-
this.customerSubscription.unsubscribe();
67+
this.loadCustomersSubscription.unsubscribe();
68+
this.changeCustomerSubscription.unsubscribe();
5569
this.dtTrigger.unsubscribe();
5670
}
5771

@@ -65,15 +79,15 @@ export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
6579
this.store.dispatch(new DeleteCustomer(customerId));
6680
}
6781

68-
rerender(): void {
82+
private rerenderDataTable(): void {
6983
if (this.isDtInitialized) {
7084
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
7185
dtInstance.destroy();
7286
this.dtTrigger.next();
7387
});
7488
} else {
75-
this.isDtInitialized = true;
7689
this.dtTrigger.next();
90+
this.isDtInitialized = true;
7791
}
7892
}
7993
}

src/styles/colors.scss

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,35 @@ $info: #00BAEE;
5151
.btn:active {
5252
border: none;
5353
}
54+
55+
56+
/**
57+
General Datatable adjustment styles
58+
*/
59+
.dataTables_wrapper {
60+
.dataTables_scroll {
61+
.dataTables_scrollBody {
62+
table {
63+
thead {
64+
display: none;
65+
}
66+
}
67+
}
68+
}
69+
}
70+
71+
.dt-buttons {
72+
.dt-button {
73+
background-image: linear-gradient($info);
74+
color: white;
75+
}
76+
.dt-button:hover:not(.disabled){
77+
background-image: linear-gradient($info);
78+
opacity: 0.5;
79+
}
80+
81+
.dt-button.disabled{
82+
background-image: linear-gradient($info);
83+
opacity: 0.5;
84+
}
85+
}

tsconfig.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@
1717
"lib": [
1818
"es2018",
1919
"dom"
20-
],
21-
"paths": {
22-
"@angular/*": [
23-
"../node_modules/@angular/*"
24-
]
25-
}
20+
]
2621
},
2722
"angularCompilerOptions": {
2823
"fullTemplateTypeCheck": true,

0 commit comments

Comments
 (0)