@itexpert-dev/base-universal-table
Version:
base universal table for build tables
256 lines (228 loc) • 10.7 kB
text/typescript
import {KeyValueStorage} from '@itexpert-dev/key-value-storage'
import {Observable, Subject, ReplaySubject} from 'rxjs'
import {UniversalTableDataPreprocessors} from './universalTableDataPreprocessors'
import {IUniversalTableParsedRequest} from "./common/interfaces/IUniversalTableParsedRequest";
import {ViewContainerRef, Injector, ComponentFactoryResolver, ReflectiveInjector} from "@angular/core";
import {UniversalTableConfigurator} from "./universalTableConfigurator/universalTableConfigurator";
import {IUniversalTableCtrl} from "../../../contracts/IUniversalTableCtrl";
import {IUniversalTableViewScope} from "../../../contracts/IUniversalTableViewScope";
import {IUniversalTableState} from "../../../contracts/IUniversalTableState";
import {IUniversalTableComponents} from "../../../contracts/IUniversalTableDefaultComponents";
import {IUniversalTableCtrlInitParams} from "../../../contracts/IUniversalTableCtrlInitParams";
import {IUniversalTableGetDataResponse} from "../../../contracts/IUniversalTableGetDataResponse";
import {IUniversalTableGetDataRequest} from "../../../contracts/IUniversalTableGetDataRequest";
import {IUniversalTableCellPosition} from "../../../contracts/IUniversalTableCellPosition";
import {IUniversalTableHeaderData} from "../../../contracts/IUniversalTableHeaderData";
class UniversalTableCtrl extends IUniversalTableCtrl{
private headers: Subject<IUniversalTableParsedRequest> = new ReplaySubject<IUniversalTableParsedRequest>(1);
private rows: Subject<IUniversalTableParsedRequest> = new ReplaySubject<IUniversalTableParsedRequest>(1);
/**
* @desc object for ui bind handlers and templates
* @type {IUniversalTableViewScope}
*/
public viewScope:IUniversalTableViewScope = {
headers: this.headers.map(next=>this.dataPreprocessors.parseHeaders(next.viewFields, next.metadata)),
rows: this.rows.map(next=>this.dataPreprocessors.parseData(next.viewFields, next)),
totalResult: 0
};
public currentState: IUniversalTableState;
public stateStream: Subject<IUniversalTableState> = new ReplaySubject<IUniversalTableState>(1);
/**
* @desc ctrl instance components for render UI
* @type {IUniversalTableComponents}
*/
public tableComponents: IUniversalTableComponents = {};
//storage for refs in template for inject components
public viewContainerRefs:KeyValueStorage<any> = new KeyValueStorage<any>();
public dataPreprocessors = UniversalTableDataPreprocessors;
public config: UniversalTableConfigurator;
public initParams: IUniversalTableCtrlInitParams;
constructor(
initParams: IUniversalTableCtrlInitParams,
config: UniversalTableConfigurator
){
super();
this.config = config;
this.initParams = initParams;
this.currentState = {};
this.stateStream.subscribe(
next=>{
Object.assign(this.currentState, next);
}
);
this.updateCurrentState({isInit: false});
//fix empty components map
if(!this.initParams.hasOwnProperty('componentsMap')){
this.initParams.componentsMap = {}
}
//apply local config by default and init config
Object.assign(
this.tableComponents,
this.config.getDefaultComponents(),
this.initParams.componentsMap
);
Object.assign(
this.currentState,
this.config.getDefaultInitTableState(),
this.initParams.initState
);
}
private updateCurrentState(state: IUniversalTableState){
this.stateStream.next(Object.assign({}, this.currentState, state));
}
public resolveInit(){
this.updateCurrentState({isInit: true});
};
private getRequireFields(state:IUniversalTableState, request: IUniversalTableGetDataResponse):string[]{
let requireFields: string[];
if (!state.hasOwnProperty('viewFields') || state.viewFields === null){
if (!state.hasOwnProperty('fields') || state.fields === null){
if (this.currentState === null || !this.currentState.hasOwnProperty('fields')){
requireFields = [];
Object.keys(request.metadata).map(
key=>requireFields.push(key)
)
} else{
requireFields = this.currentState.fields
}
}else{
requireFields = state.fields
}
} else {
requireFields = state.viewFields
}
return requireFields
}
public updateState(
state: IUniversalTableState = {},
options:{enableStateDiff: boolean} = {enableStateDiff: true}
):Observable<null>{
let newState: IUniversalTableState = {};
if(options.enableStateDiff === true){
let diff: IUniversalTableState = {};
let anyDiff:boolean = false;
Object.keys(state).map(key=>{
let val = (state as any)[key];
if((this.currentState as any)[key]!==val){
anyDiff = true;
(diff as any)[key] = val
}
});
if(anyDiff){
return this.setState(Object.assign({}, this.currentState, diff))
}else{
return Observable.empty()
}
}else{
Object.assign(newState, this.currentState, state);
}
return this.setState(newState)
}
private setState(state: IUniversalTableState):Observable<null>{
this.updateCurrentState({isUpdate: true});
let query:IUniversalTableGetDataRequest = {
fields: state.fields,
filter: state.filter,
limit: state.limit,
offset: state.offset,
sort: state.sort
};
return this.initParams
//send request to server
.getDataMethod(query)
//append state to query with actual totalResult
.map(next=>{
return Object.assign(next, {
state: Object.assign(state, {
totalResult: next.totalResult
})
})
})
// calculate actual view fields
.map(next=>{
let result: IUniversalTableParsedRequest = Object.assign(next, {
viewFields: this.getRequireFields(next.state, next)
});
return result
})
// publish new data to UI binding stream
.do((next)=>{
this.headers.next(next);
this.rows.next(next);
this.updateCurrentState(Object.assign(next.state, {isUpdate: false}));
})
.pluck('state')
}
public printContainer(container: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, parentInjector: Injector){
let componentKey = this.tableComponents.container;
let componentFactory = this.config.componentsStorage.getComponent(componentKey);
let injector = ReflectiveInjector.resolveAndCreate(
[{
provide: IUniversalTableCtrl,
useValue: this
}],
parentInjector
);
let component = componentFactoryResolver.resolveComponentFactory(<any>componentFactory);
container.createComponent(component, 0, injector);
}
public printPaginator(container: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, parentInjector: Injector){
let componentKey = this.tableComponents.paginator;
let componentFactory = this.config.componentsStorage.getComponent(componentKey);
let injector = ReflectiveInjector.resolveAndCreate(
[{
provide: IUniversalTableCtrl,
useValue: this
}],
parentInjector
);
let component = componentFactoryResolver.resolveComponentFactory(<any>componentFactory);
container.createComponent(component, 0, injector);
}
public printCell(container: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, parentInjector: Injector, cellPosition: IUniversalTableCellPosition){
let componentKey = this.tableComponents.cell;
let componentFactory = this.config.componentsStorage.getComponent(componentKey);
let injector = ReflectiveInjector.resolveAndCreate(
[{
provide: IUniversalTableCtrl,
useValue: this
},{
provide: IUniversalTableCellPosition,
useValue: cellPosition
}],
parentInjector
);
let component = componentFactoryResolver.resolveComponentFactory(<any>componentFactory);
container.createComponent(component, 0, injector);
}
public printGrid(container: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, parentInjector: Injector){
let componentKey = this.tableComponents.grid;
let componentFactory = this.config.componentsStorage.getComponent(componentKey);
let injector = ReflectiveInjector.resolveAndCreate(
[{
provide: IUniversalTableCtrl,
useValue: this
}],
parentInjector
);
let component = componentFactoryResolver.resolveComponentFactory(<any>componentFactory);
container.createComponent(component, 0, injector);
}
public printHeader(container: ViewContainerRef, componentFactoryResolver: ComponentFactoryResolver, parentInjector: Injector, headerData: IUniversalTableHeaderData){
let componentKey = this.tableComponents.headers;
let componentFactory = this.config.componentsStorage.getComponent(componentKey);
let injector = ReflectiveInjector.resolveAndCreate(
[{
provide: IUniversalTableCtrl,
useValue: this
},{
provide: IUniversalTableHeaderData,
useValue: headerData
}],
parentInjector
);
let component = componentFactoryResolver.resolveComponentFactory(<any>componentFactory);
container.createComponent(component, 0, injector);
}
}
export {UniversalTableCtrl}