Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat: #228 Adding angular datatables to customer list component
  • Loading branch information
Juan Gabriel Guzman committed May 20, 2020
commit a93d03e648d40ff7bc0021f4e0e65cca91212f7d
11 changes: 9 additions & 2 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@
"node_modules/datatables.net-dt/css/jquery.dataTables.css",
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss",
"node_modules/ngx-toastr/toastr.css"
"node_modules/ngx-toastr/toastr.css",
"node_modules/datatables.net-buttons-dt/css/buttons.dataTables.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.js",
"./node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/datatables.net/js/jquery.dataTables.js"
"node_modules/datatables.net/js/jquery.dataTables.js",
"node_modules/jszip/dist/jszip.js",
"node_modules/datatables.net-buttons/js/dataTables.buttons.js",
"node_modules/datatables.net-buttons/js/buttons.colVis.js",
"node_modules/datatables.net-buttons/js/buttons.flash.js",
"node_modules/datatables.net-buttons/js/buttons.html5.js",
"node_modules/datatables.net-buttons/js/buttons.print.js"
]
},
"configurations": {
Expand Down
5,610 changes: 5,593 additions & 17 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,17 @@
"ngx-toastr": "^12.0.1",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
"zone.js": "~0.10.2",
"jszip": "^3.4.0",
"datatables.net-buttons": "^1.6.2",
"datatables.net-buttons-dt": "^1.6.2",
"@types/datatables.net-buttons": "^1.4.3"
},
"devDependencies": {
"angular-datatables": "^9.0.2",
"jquery": "^3.5.1",
"datatables.net": "^1.10.21",
"datatables.net-dt": "^1.10.21",
"@angular-devkit/build-angular": "^0.900.5",
"@angular/cli": "~9.0.4",
"@angular/compiler-cli": "~9.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<thead class="thead-orange">
<tr class="d-flex">
<th class="col-9">Name</th>
<th class="col-3 text-center"></th>
<th class="col-3 text-center">Options</th>
</tr>
</thead>
<tbody>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
@import '../../../../../../../styles/colors.scss';
Original file line number Diff line number Diff line change
@@ -1,58 +1,65 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';

import { NgxPaginationModule } from 'ngx-pagination';
import { CustomerListComponent } from './customer-list.component';
import { allCustomers } from './../../../../store/customer-management.selectors';
import { CustomerState, SetCustomerToEdit, DeleteCustomer } from 'src/app/modules/customer-management/store';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {MockStore, provideMockStore} from '@ngrx/store/testing';

import {NgxPaginationModule} from 'ngx-pagination';
import {CustomerListComponent} from './customer-list.component';
import {allCustomers} from './../../../../store/customer-management.selectors';
import {
CustomerState,
SetCustomerToEdit,
DeleteCustomer,
LoadCustomers,
CustomerManagementActionTypes
} from 'src/app/modules/customer-management/store';
import {DataTablesModule} from 'angular-datatables';
import {ActionsSubject} from '@ngrx/store';

describe('CustomerTableListComponent', () => {
let component: CustomerListComponent;
let fixture: ComponentFixture<CustomerListComponent>;
let store: MockStore<CustomerState>;
let mockCustomerSelector;
const actionSub: ActionsSubject = new ActionsSubject();

const state = {
data: [{ tenant_id: 'id', name: 'name', description: 'description' }],
data: [{tenant_id: 'id', name: 'name', description: 'description'}],
isLoading: false,
message: '',
customerIdToEdit: '',
customerId: ''
};



beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [NgxPaginationModule],
imports: [NgxPaginationModule, DataTablesModule],
declarations: [CustomerListComponent],
providers: [
provideMockStore({ initialState: state })
provideMockStore({initialState: state}),
{provide: ActionsSubject, useValue: actionSub}
],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(CustomerListComponent);
component = fixture.componentInstance;
fixture.detectChanges();

store = TestBed.inject(MockStore);
store.setState(state);
mockCustomerSelector = store.overrideSelector(allCustomers, state.data);
fixture.detectChanges();

});

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

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

component.ngOnInit();

expect(store.dispatch).toHaveBeenCalled();
expect(component.customers).toEqual(state.data);
expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
});

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

const params = [
{actionName: 'delete', actionType: CustomerManagementActionTypes.DELETE_CUSTOMER_SUCCESS},
{actionName: 'update', actionType: CustomerManagementActionTypes.UPDATE_CUSTOMER_SUCCESS},
{actionName: 'create', actionType: CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS}
];

params.map(param =>
it(`on success ${param.actionName} customer, the load all customer action should be triggered`, () => {
const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
const action = {
type: param.actionType
};
spyOn(store, 'dispatch');

actionSubject.next(action);

expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
}));

params.map(param =>
it(`on success ${param.actionName} customer, the customer form should be disabled`, () => {
const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
const action = {
type: param.actionType
};
actionSubject.next(action);

expect(component.showCustomerForm).toBe(false);
}));

// TODO Make this test work. This is having problems with jquery integration
// it('on success load customers, the customer list should be populated', () => {
// const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
// const action = {
// type: CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS,
// payload: state.data
// };
//
// actionSubject.next(action);
//
// expect(component.customers).toEqual(state.data);
// });

afterEach(() => {
component.dtTrigger.unsubscribe();
component.changeCustomerSubscription.unsubscribe();
component.loadCustomersSubscription.unsubscribe();
fixture.destroy();
});
});
Original file line number Diff line number Diff line change
@@ -1,57 +1,71 @@
import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, ViewChild, AfterViewInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { DataTableDirective } from 'angular-datatables';
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild} from '@angular/core';
import {ActionsSubject, Store} from '@ngrx/store';

import { Subscription, Subject } from 'rxjs';
import { allCustomers } from './../../../../store/customer-management.selectors';
import { LoadCustomers, DeleteCustomer, SetCustomerToEdit } from './../../../../store/customer-management.actions';
import { Customer } from './../../../../../shared/models/customer.model';
import { ITEMS_PER_PAGE } from 'src/environments/environment';
import {ToastrService} from 'ngx-toastr';
import {Subject, Subscription} from 'rxjs';
import {
CustomerManagementActionTypes,
DeleteCustomer,
LoadCustomers,
SetCustomerToEdit
} from './../../../../store/customer-management.actions';
import {Customer} from './../../../../../shared/models/customer.model';
import {filter} from 'rxjs/operators';
import {DataTableDirective} from 'angular-datatables';

@Component({
selector: 'app-customer-list',
templateUrl: './customer-list.component.html',
styleUrls: ['./customer-list.component.scss'],
})
export class CustomerListComponent implements OnInit, OnDestroy, AfterViewInit {
initPage1 = 1;
itemsPerPage = ITEMS_PER_PAGE;
export class CustomerListComponent implements OnInit, OnDestroy {

@Input() showCustomerForm: boolean;
@Output() changeValueShowCustomerForm = new EventEmitter<boolean>();

@Input()
customers: Customer[] = [];
customerSubscription: Subscription;
dtOptions: DataTables.Settings = {};
dtOptions: any = {};
dtTrigger: Subject<any> = new Subject();
@ViewChild(DataTableDirective, {static: false})
dtElement: DataTableDirective;
isDtInitialized = false;
loadCustomersSubscription: Subscription;
changeCustomerSubscription: Subscription;

constructor(private store: Store<Customer>, private toastrService: ToastrService) {

constructor(private store: Store<Customer>, private actionsSubject$: ActionsSubject) {
}

ngOnInit(): void {
this.dtOptions = {
scrollY: '250px',
paging: false,
scrollY: '290px',
paging: false
};

this.store.dispatch(new LoadCustomers());
const customers$ = this.store.pipe(select(allCustomers));
this.customerSubscription = customers$.subscribe((response) => {
this.customers = response ? response : [];
this.rerender();
this.loadCustomersSubscription = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS
)
)
).subscribe((action) => {
this.customers = action.payload;
this.rerenderDataTable();
});
}

ngAfterViewInit(): void {
this.dtTrigger.next();
this.changeCustomerSubscription = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === CustomerManagementActionTypes.DELETE_CUSTOMER_SUCCESS ||
action.type === CustomerManagementActionTypes.UPDATE_CUSTOMER_SUCCESS ||
action.type === CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS
)
)
).subscribe((action) => {
this.store.dispatch(new LoadCustomers());
this.showCustomerForm = false;
});
this.store.dispatch(new LoadCustomers());
}

ngOnDestroy() {
this.customerSubscription.unsubscribe();
this.loadCustomersSubscription.unsubscribe();
this.changeCustomerSubscription.unsubscribe();
this.dtTrigger.unsubscribe();
}

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

rerender(): void {
private rerenderDataTable(): void {
if (this.isDtInitialized) {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
this.dtTrigger.next();
});
} else {
this.isDtInitialized = true;
this.dtTrigger.next();
this.isDtInitialized = true;
}
}
}
32 changes: 32 additions & 0 deletions src/styles/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,35 @@ $info: #00BAEE;
.btn:active {
border: none;
}


/**
General Datatable adjustment styles
*/
.dataTables_wrapper {
.dataTables_scroll {
.dataTables_scrollBody {
table {
thead {
display: none;
}
}
}
}
}

.dt-buttons {
.dt-button {
background-image: linear-gradient($info);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should replace this by:
background-color: $info

color: white;
}
.dt-button:hover:not(.disabled){
background-image: linear-gradient($info);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should replace this by:
background-color: $info

opacity: 0.5;
}

.dt-button.disabled{
background-image: linear-gradient($info);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should replace this by:
background-color: $info

opacity: 0.5;
}
}