Page MenuHomec4science

navigation-list-component.component.ts
No OneTemporary

File Metadata

Created
Fri, Jul 5, 18:47

navigation-list-component.component.ts

import {NAVTREE_DEFS} from '../constants';
import {Component, EventEmitter, OnInit} from '@angular/core';
import {NavigationServiceService} from '../services/navigation-service.service';
import {NavigationEntity, NavTreeDef, TlnEntity} from '../models/models';
import {Subscription} from 'rxjs/index';
import {ActivatedRoute, ParamMap, Router} from '@angular/router';
import {QueryService} from '../services/query.service';
import {NavTree} from './navtree-directive.directive';
import * as _ from 'lodash';
@Component({
selector: 'app-navigation-list-component',
templateUrl: './navigation-list-component.component.html',
styleUrls: ['./navigation-list-component.component.scss']
})
/**
* NavigationListComponent
* Builds/rebuilds the navigation trees for populating the navigationlist-list-component and reacts on changes in the url
*/
export class NavigationListComponentComponent implements OnInit {
navigationTreeDefs: NavTreeDef[]; // The definitions for buildling the navTrees
navTrees: NavTree[]; // The actual Navtrees which are displayed
activeTree: NavTree; // the tree which is displayed in the list component
navTabIndex: number; // the index of the active tree in navTrees
navTabIndexChange: EventEmitter<number>;
oldQueryParams: ParamMap;
queryParamSubscription: Subscription;
constructor(public naviService: NavigationServiceService,
private router: Router,
private activatedRoute: ActivatedRoute,
private queryService: QueryService) {
this.navigationTreeDefs = NAVTREE_DEFS;
this.navTabIndexChange = new EventEmitter<number>();
}
ngOnInit() {
this.oldQueryParams = this.activatedRoute.snapshot.queryParamMap;
this.queryParamSubscription = this.activatedRoute.queryParamMap.subscribe((queryParams: ParamMap) => {
this.reactOnNewQParams(queryParams);
});
// The navTabIndex and the activeTree are set accordingly on the emitted tabIndex
this.navTabIndexChange.subscribe(tabIdx => {
if (tabIdx !== this.navTabIndex && tabIdx < this.navTrees.length && tabIdx >= 0) {
this.navTabIndex = tabIdx;
this.activeTree = this.navTrees[tabIdx];
}
});
this.initNavTrees();
}
//
// INITIAL METHODS, CORE METHODS
//
async initNavTrees() {
await this.createTreesOnInit();
await this.populateNavTrees();
await this.setActiveTreeOnInit();
this.subscribeToSetSelectedItems();
}
createTreesOnInit() {
this.navTrees = [];
this.navigationTreeDefs.forEach(def =>
this.navTrees.push(new NavTree(def.id, def.idx, def.label, [], def.itemQParam, def.description, def.apiDef)));
}
/**
* populateNavTrees creates the first trees if no query params are available in the url:
* It ceates the manuscripNavTree and the activePageNavTreeData of the first manuscript per default.
*
*/
async populateNavTrees(tabIdx?: number, item?: TlnEntity) {
const tabStartIndex = tabIdx || 0; // where to start refreshing navtrees downward
for (const treeDef of this.navigationTreeDefs.sort(def => (def.idx))) {
if (treeDef.idx >= tabStartIndex) { // only create trees if needed
this.queryService.getQueryfromFilename(treeDef.apiDef.query).subscribe(async query => {
let queryToRun: string;
// If there is a selectedItem we have to parametrize the query
if (treeDef.idx > 0) { // so we have to parametrize the query
if (item) {
queryToRun = this.queryService.parametrizeQueryWithItem(query, item.id);
this.populateNavTree(treeDef, queryToRun);
} else {
// wait for selected item of the previous tab and parametrize then the query
this.navTrees[treeDef.idx - 1].selectedItemSet.subscribe(selItem => {
if (selItem.tabId === treeDef.idx - 1) {
queryToRun = this.queryService.parametrizeQueryWithItem(query, selItem.itemId);
this.populateNavTree(treeDef, queryToRun);
}
});
}
} else {
this.populateNavTree(treeDef, query);
}
});
}
}
}
populateNavTree(def: NavTreeDef, query) {
const idx = this.navTrees.findIndex(navTreeId => navTreeId.id === def.id);
let parentLabel;
if (idx > 0) {
parentLabel = this.navTrees[idx - 1].selectedItemLabel;
}
if (idx !== -1) {
this.queryService.getData(def.apiDef.baseUrl, query, 'SELECT').subscribe(data => {
this.navTrees[idx].setNavTreeData(_.get(data, def.apiDef.dataArray),
this.activatedRoute.snapshot.queryParams, parentLabel);
});
}
}
/**
* setActiveTreeOnInit listens to the initial queryParam and sets the navTabIdx accordingly.
* gets the active navTabIndex either from a passed contextView, from active qParam or sets it to 0
*/
private setActiveTreeOnInit() {
const activeTab = parseInt(this.activatedRoute.snapshot.queryParamMap.get('navTabIdx'), 10);
this.navTrees.forEach(tree => {
// If the tree is the active one according to qParam 'navTabIdx, we change to that tree
if (activeTab === tree.idx) {
this.navTabIndexChange.emit(activeTab);
}
});
}
/**
* subscribeToSetSelectedItems
* Subscribe to each tree's selectedItemSet and route/set the selectedItem in the qParams if the item is not yet set
* This applies when the trees are built initially or rebuilt, i.e. in two cases:
* 1) when no qParam for the trees is set in the route
* 2) a selected item is changed in a parent tree and the childs qParams are nulled
*/
private subscribeToSetSelectedItems() {
this.navTrees.forEach(tree => {
if (!this.activatedRoute.snapshot.queryParamMap.get(tree.qParam)) {
tree.selectedItemSet.subscribe(item => {
// set qParam
this.naviService.updateRoute({[tree.qParam]: item.itemId});
});
}
});
}
//
// REACTING ON CHANGES MADE OUTSIDE OF THE COMPONENT
//
async reactOnNewQParams(qParams: ParamMap) {
// iterating through all queryParams and react if one param has changed
await qParams.keys.forEach(key => {
if (qParams.get(key) !== this.oldQueryParams.get(key)) {
this.reactOnParamChange(key, qParams.get(key));
}
}
);
this.oldQueryParams = this.activatedRoute.snapshot.queryParamMap;
}
reactOnParamChange(qParam: string, newValue: string) {
// qParams of the navTrees, e.g. 'page' and 'manuscript'
if (this.navTrees && this.navTrees.map(tree => tree.qParam).findIndex(param => param === qParam) !== -1) {
// if a qParam is one of the params defined in navTrees
this.reactOnItemChange(qParam, newValue);
}
if (qParam === 'contextView') {
this.reactOnContextChange(newValue);
}
if (qParam === 'navTabIdx') {
this.navTabIndexChange.emit(parseInt(newValue, 10));
}
}
reactOnItemChange(param: string, itemId: string) {
// because it might be changed from outside via url update, we have to find the tree according to the changed param
const parentIdx = this.navTrees.findIndex(tree => tree.qParam === param);
if (itemId !== this.navTrees[parentIdx].selectedItem) { // only rebuild if it is not yet set.
this.rebuildTrees(parentIdx, itemId);
}
}
// gets the
reactOnContextChange(context: string) {
const newTabIndex = this.getActiveNavTabIdxFromContext(context);
this.changeNavTreeViaRoute(newTabIndex);
// must time out here hence document is not ready to scroll
// window.setTimeout(() => this.scrollOnToSelectedItem(this.oldQueryParams[context]), 100);
}
async rebuildTrees(parentIdx, itemId) {
const itemToSelect = await this.navTrees[parentIdx].getSelectedById(itemId);
await this.navTrees[parentIdx].setSelectedItem(itemToSelect.tlnEntity.id, itemToSelect.tlnEntity.label);
await this.rebuildChildNavTrees(itemToSelect, parentIdx);
}
async rebuildChildNavTrees(item: NavigationEntity, parentIdx) {
// get new data for subTrees and set new params accordingly
await this.emptyChildTrees(parentIdx);
await this.removeAllChildTreeQParams(parentIdx);
await this.populateChildren(parentIdx, item.tlnEntity);
}
removeAllChildTreeQParams(tabId) {
this.navTrees.forEach((tree, index) => {
if (tree.idx > tabId) {
this.navTrees[index].selectedItem = null;
this.naviService.updateRoute({[tree.qParam]: null});
}
});
}
emptyChildTrees(parentIdx) {
this.navTrees.forEach((tree, index) => {
if (tree.idx > parentIdx) {
this.navTrees[index].entries = [];
}
});
}
populateChildren(parentTab, item: TlnEntity) {
if (parentTab + 1 < this.navigationTreeDefs.length) {
// if an item in a tab with sub tabs is selected, the subtree should be loaded according to that selection and the tab should change
this.populateNavTrees(parentTab + 1, item);
}
}
/**
* getActiveNavTabIndexOnInit
* gets the active navTabIndex either from a passed contextView, from active qParam or sets it to 0
*/
getActiveNavTabIdxFromContext(con: string) {
let navTreeIndex; // the index of the navTree with the qParam corresponding to con
let navTabIndex;
if (con) {
navTreeIndex = this.navigationTreeDefs.findIndex(tree => tree.itemQParam === con);
}
if (navTreeIndex >= 0) { // no -1/not found
navTabIndex = this.navigationTreeDefs[navTreeIndex].idx;
}
return navTabIndex;
}
/**
* changeNavTreeViaRoute
* changes to a new tree/tab in the navtab of the navList. In case of displayed tln-search and tln-crossRef
* within content-view-component, the contextView is set also corresponding to the trees qParam.
*/
changeNavTreeViaRoute(idx: number) {
if (idx < this.navTrees.length && idx >= 0) {
const qParams = {};
qParams['navTabIdx'] = idx;
const activeView = this.activatedRoute.snapshot.children.pop().routeConfig.path;
// If the tln-search or the tln-crossRef are active, then change the contextView, hence the app reacts
// on context change and will set the navTabIdx accordingly
if ( activeView === 'tln-search' || activeView === 'tln-crossref' ) {
const newContext = this.navTrees[this.navTrees.findIndex(tree => tree.idx === idx)].qParam;
if (newContext !== this.activatedRoute.snapshot.queryParamMap.get('contextView')) {
qParams['contextView'] = newContext;
}
}
this.naviService.updateRoute(qParams);
}
}
}

Event Timeline