-
-<h1>CATALOG</h1>
+<eg-catalog-search-form></eg-catalog-search-form>
<router-outlet></router-outlet>
+
import {EgCatalogRoutingModule} from './routing.module';
import {EgUnapiService} from '@eg/share/unapi';
import {EgCatalogComponent} from './catalog.component';
-import {EgCatalogSearchComponent} from './search.component';
+import {EgCatalogSearchFormComponent} from './search-form.component';
+import {EgCatalogResultsComponent} from './results.component';
import {EgCatalogService} from './catalog.service';
@NgModule({
declarations: [
EgCatalogComponent,
- EgCatalogSearchComponent
+ EgCatalogSearchFormComponent,
+ EgCatalogResultsComponent
],
imports: [
EgStaffModule,
import {EgIdlObject} from '@eg/core/idl';
import {EgNetService} from '@eg/core/net';
import {EgPcrudService} from '@eg/core/pcrud';
+import {SearchContext} from './search-context';
const CCVM_FILTER_TYPES = [
'item_type',
'search_format'
];
-class Paginator {
- offset: number = 0;
- limit: number = 15;
- resultCount: number;
-
- isFirstPage(): boolean {
- return this.offset == 0;
- }
-
- isLastPage(): boolean {
- return this.currentPage() == this.pageCount();
- }
-
- currentPage(): number {
- return Math.floor(this.offset / this.limit) + 1
- }
-
- pageCount(): number {
- let pages = this.resultCount / this.limit;
- if (Math.floor(pages) < pages)
- pages = Math.floor(pages) + 1;
- return pages;
- }
-
- pageList(): number[] {
- let list = [];
- for(let i = 1; i <= this.pageCount(); i++)
- list.push(i);
- return list;
- }
-}
-
-export class FacetFilter {
- facetClass: string;
- facetName: string;
- facetValue: string;
-}
-
-export class CatalogContext {
- available: boolean = false;
- global: boolean = false;
- sort: string;
- searchClass: string[];
- query: string[];
- joiner: string[];
- match: string[];
- format: string;
- searchOrg: EgIdlObject;
- ccvmFilters: {[ccvm:string] : string} = {};
- facetFilters: FacetFilter[] = [];
- paginator: Paginator = new Paginator();
- result: any;
- org: EgOrgService;
-
- compileSearch(): string {
-
- let str: string = '';
-
- if (this.available) str += ' #available';
-
- if (this.sort) {
- // e.g. title, title.descending
- let parts = this.sort.split(/\./);
- if (parts[1]) str += ' #descending';
- str += ' sort(' + parts[0] + ')';
- }
-
- // -------
- // Compile boolean sub-query components
- if (str.length) str += ' ';
- let qcount = this.query.length;
-
- // if we multiple boolean query components, wrap them in parens.
- if (qcount > 1) str += '(';
- this.query.forEach((q, idx) => {
- str += this.compileBoolQuerySet(idx)
- });
- if (qcount > 1) str += ')';
- // -------
-
- if (this.format) {
- str += ' format(' + this.format + ')';
- }
-
- if (this.global) {
- str += ' depth(' +
- this.org.root().ou_type().depth() + ')';
- }
-
- str += ' site(' + this.searchOrg.shortname() + ')';
-
- Object.keys(this.ccvmFilters).forEach(field => {
- str += ' ' + field + '(' + this.ccvmFilters[field] + ')';
- });
-
- this.facetFilters.forEach(f => {
- str += ' ' + f.facetClass + '|'
- + f.facetName + '[' + f.facetValue + ']';
- });
-
- return str;
- }
-
- stripQuotes(query: string): string {
- return query.replace(/"/g, '');
- }
-
- stripAnchors(query: string): string {
- return query.replace(/[\^\$]/g, '');
- }
-
- addQuotes(query: string): string {
- if (query.match(/ /))
- return '"' + query + '"'
- return query;
- };
-
- compileBoolQuerySet(idx: number): string {
- let query = this.query[idx];
- let joiner = this.joiner[idx];
- let match = this.match[idx];
- let searchClass = this.searchClass[idx];
-
- let str = '';
- if (!query) return str;
-
- if (idx > 0) str += ' ' + joiner + ' ';
-
- str += '(';
- if (searchClass) str += searchClass + ':';
-
- switch(match) {
- case 'phrase':
- query = this.addQuotes(this.stripQuotes(query));
- break;
- case 'nocontains':
- query = '-' + this.addQuotes(this.stripQuotes(query));
- break;
- case 'exact':
- query = '^' + this.stripAnchors(query) + '$';
- break;
- case 'starts':
- query = this.addQuotes('^' +
- this.stripAnchors(this.stripQuotes(query)));
- break;
- }
-
- return str + query + ')';
- }
-}
-
-
@Injectable()
export class EgCatalogService {
+ searchContext: SearchContext;
ccvmMap: {[ccvm:string] : EgIdlObject[]} = {};
cmfMap: {[cmf:string] : EgIdlObject[]} = {};
private org: EgOrgService,
private unapi: EgUnapiService,
private pcrud: EgPcrudService
- ) {}
-
+ ) {
+ this.searchContext = new SearchContext();
+ this.searchContext.org = this.org;
+ }
- search(context: CatalogContext): Promise<void> {
+ search(context: SearchContext): Promise<void> {
var fullQuery = context.compileSearch();
this.net.request(
'open-ils.search',
'open-ils.search.biblio.multiclass.query.staff', {
- limit : context.paginator.limit,
- offset : context.paginator.offset
+ limit : context.pager.limit,
+ offset : context.pager.offset
}, fullQuery, true
).subscribe(result => {
context.result = result;
context.result.records = [];
- context.paginator.resultCount = result.count;
+ context.pager.resultCount = result.count;
let promises = [];
result.ids.forEach(blob => {
this.pcrud.search('ccvm',
{ctype : CCVM_FILTER_TYPES}, {}, {atomic: true}
).subscribe(list => {
- console.debug(list);
this.compileCcvms(list);
resolve();
})
--- /dev/null
+import {Injectable} from '@angular/core';
+import {Location} from '@angular/common';
+import {Observable, Observer} from 'rxjs/Rx';
+import {Router, Resolve, RouterStateSnapshot,
+ ActivatedRouteSnapshot} from '@angular/router';
+import {EgStoreService} from '@eg/core/store';
+import {EgNetService} from '@eg/core/net';
+import {EgAuthService} from '@eg/core/auth';
+import {EgPcrudService} from '@eg/core/pcrud';
+import {EgCatalogService} from './catalog.service'
+
+@Injectable()
+export class EgCatalogResolver implements Resolve<Promise<any[]>> {
+
+ constructor(
+ private router: Router,
+ private ngLocation: Location,
+ private store: EgStoreService,
+ private net: EgNetService,
+ private auth: EgAuthService,
+ private cat: EgCatalogService
+ ) {}
+
+ resolve(
+ route: ActivatedRouteSnapshot,
+ state: RouterStateSnapshot): Promise<any[]> {
+
+ console.debug('EgCatalogResolver:resolve()');
+
+ return Promise.all([
+ this.cat.fetchCcvms()
+ ]);
+ }
+}
+
--- /dev/null
+
+<h2>Search Sample</h2>
+
+<div *ngIf="searchContext.result">
+ <div class="row"
+ *ngFor="let record of searchContext.result.records; let idx = index">
+ <div class="col-1">{{idx + 1}}</div>
+ <div class="col-3">{{record.title}}</div>
+ <div class="col-3">{{record.author}}</div>
+ <div class="col-3">{{record.genre}}</div>
+ </div>
+</div>
+
--- /dev/null
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {EgAuthService} from '@eg/core/auth';
+import {EgOrgService} from '@eg/core/org';
+import {EgCatalogService} from './catalog.service';
+import {SearchContext} from './search-context';
+
+@Component({
+ templateUrl: 'results.component.html'
+})
+export class EgCatalogResultsComponent implements OnInit {
+
+ searchContext: SearchContext;
+
+ constructor(
+ private auth: EgAuthService,
+ private org: EgOrgService,
+ private cat: EgCatalogService
+ ) {
+ this.searchContext = this.cat.searchContext;
+ }
+
+ ngOnInit() {
+ }
+}
+
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {EgCatalogComponent} from './catalog.component';
-import {EgCatalogSearchComponent} from './search.component';
+import {EgCatalogResultsComponent} from './results.component';
+import {EgCatalogResolver} from './resolver.service';
const routes: Routes = [{
path: '',
component: EgCatalogComponent,
+ resolve: {catResolver : EgCatalogResolver},
children : [{
path: 'search',
- component: EgCatalogSearchComponent,
+ component: EgCatalogResultsComponent,
}]
}];
@NgModule({
- imports: [ RouterModule.forChild(routes) ],
- exports: [ RouterModule ]
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+ providers: [EgCatalogResolver ]
})
export class EgCatalogRoutingModule {}
--- /dev/null
+import {EgOrgService} from '@eg/core/org';
+import {EgIdlObject} from '@eg/core/idl';
+
+class Pager {
+ offset: number = 0;
+ limit: number = 15;
+ resultCount: number;
+
+ isFirstPage(): boolean {
+ return this.offset == 0;
+ }
+
+ isLastPage(): boolean {
+ return this.currentPage() == this.pageCount();
+ }
+
+ currentPage(): number {
+ return Math.floor(this.offset / this.limit) + 1
+ }
+
+ pageCount(): number {
+ let pages = this.resultCount / this.limit;
+ if (Math.floor(pages) < pages)
+ pages = Math.floor(pages) + 1;
+ return pages;
+ }
+
+ pageList(): number[] {
+ let list = [];
+ for(let i = 1; i <= this.pageCount(); i++)
+ list.push(i);
+ return list;
+ }
+}
+
+interface FacetFilter {
+ facetClass: string;
+ facetName: string;
+ facetValue: string;
+}
+
+
+export class SearchContext {
+ available: boolean;
+ global: boolean;
+ sort: string;
+ searchClass: string[];
+ query: string[];
+ joiner: string[];
+ match: string[];
+ format: string;
+ searchOrg: EgIdlObject;
+ ccvmFilters: {[ccvm:string] : string};
+ facetFilters: FacetFilter[];
+ pager: Pager;
+ org: EgOrgService;
+ result: any;
+
+ constructor() {
+ this.pager = new Pager();
+ this.reset();
+ }
+
+ reset(): void {
+ this.pager.offset = 0,
+ this.format = '',
+ this.sort = '',
+ this.query = [''];
+ this.searchClass = ['keyword'];
+ this.match = ['contains'];
+ this.joiner = [''];
+ this.available = false;
+ this.global = false;
+ this.ccvmFilters = {};
+ this.facetFilters = [];
+ }
+
+ compileSearch(): string {
+
+ let str: string = '';
+
+ if (this.available) str += ' #available';
+
+ if (this.sort) {
+ // e.g. title, title.descending
+ let parts = this.sort.split(/\./);
+ if (parts[1]) str += ' #descending';
+ str += ' sort(' + parts[0] + ')';
+ }
+
+ // -------
+ // Compile boolean sub-query components
+ if (str.length) str += ' ';
+ let qcount = this.query.length;
+
+ // if we multiple boolean query components, wrap them in parens.
+ if (qcount > 1) str += '(';
+ this.query.forEach((q, idx) => {
+ str += this.compileBoolQuerySet(idx)
+ });
+ if (qcount > 1) str += ')';
+ // -------
+
+ if (this.format) {
+ str += ' format(' + this.format + ')';
+ }
+
+ if (this.global) {
+ str += ' depth(' +
+ this.org.root().ou_type().depth() + ')';
+ }
+
+ str += ' site(' + this.searchOrg.shortname() + ')';
+
+ Object.keys(this.ccvmFilters).forEach(field => {
+ str += ' ' + field + '(' + this.ccvmFilters[field] + ')';
+ });
+
+ this.facetFilters.forEach(f => {
+ str += ' ' + f.facetClass + '|'
+ + f.facetName + '[' + f.facetValue + ']';
+ });
+
+ return str;
+ }
+
+ stripQuotes(query: string): string {
+ return query.replace(/"/g, '');
+ }
+
+ stripAnchors(query: string): string {
+ return query.replace(/[\^\$]/g, '');
+ }
+
+ addQuotes(query: string): string {
+ if (query.match(/ /))
+ return '"' + query + '"'
+ return query;
+ };
+
+ compileBoolQuerySet(idx: number): string {
+ let query = this.query[idx];
+ let joiner = this.joiner[idx];
+ let match = this.match[idx];
+ let searchClass = this.searchClass[idx];
+
+ let str = '';
+ if (!query) return str;
+
+ if (idx > 0) str += ' ' + joiner + ' ';
+
+ str += '(';
+ if (searchClass) str += searchClass + ':';
+
+ switch(match) {
+ case 'phrase':
+ query = this.addQuotes(this.stripQuotes(query));
+ break;
+ case 'nocontains':
+ query = '-' + this.addQuotes(this.stripQuotes(query));
+ break;
+ case 'exact':
+ query = '^' + this.stripAnchors(query) + '$';
+ break;
+ case 'starts':
+ query = this.addQuotes('^' +
+ this.stripAnchors(this.stripQuotes(query)));
+ break;
+ }
+
+ return str + query + ')';
+ }
+}
+
+
--- /dev/null
+
+<style>
+ /** TODO: clean up some inline styles */
+
+ #staffcat-search-form .eg-org-selector,
+ #staffcat-search-form .eg-org-selector button {
+ width: 100%;
+ text-align: left
+ }
+ .flex-row {
+ display: flex;
+ }
+ .flex-cell {
+ /* override style.css padding:4px */
+ flex: 1;
+ padding: 0px 0px 0px 8px;
+ }
+ .flex-2 {
+ flex: 2
+ }
+ .flex-row:first-child {
+ padding-left: 0px;
+ }
+</style>
+<div id='staffcat-search-form'>
+ <div class="row"
+ *ngFor="let q of searchContext.query; let idx = index; trackBy:trackByIdx">
+ <div class="col-9 flex-row">
+ <div class="flex-cell">
+ <div *ngIf="idx == 0">
+ <select class="form-control" [(ngModel)]="searchContext.format">
+ <option value=''>All Formats</option>
+ <option *ngFor="let fmt of ccvmMap.search_format"
+ value="{{fmt.code()}}">{{fmt.value()}}</option>
+ </select>
+ </div>
+ <div *ngIf="idx > 0">
+ <select class="form-control"
+ [(ngModel)]="searchContext.joiner[idx]">
+ <option value='&&'>And</option>
+ <option value='||'>Or</option>
+ </select>
+ </div>
+ </div>
+ <div class="flex-cell">
+ <select class="form-control"
+ [(ngModel)]="searchContext.searchClass[idx]">
+ <option value='keyword'>Keyword</option>
+ <option value='title'>Title</option>
+ <option value='jtitle'>Journal Title</option>
+ <option value='author'>Author</option>
+ <option value='subject'>Subject</option>
+ <option value='series'>Series</option>
+ </select>
+ </div>
+ <div class="flex-cell">
+ <select class="form-control"
+ [(ngModel)]="searchContext.match[idx]">
+ <option value='contains'>Contains</option>
+ <option value='nocontains'>Does not contain</option>
+ <option value='phrase'>Contains phrase</option>
+ <option value='exact'>Matches exactly</option>
+ <option value='starts'>Starts with</option>
+ </select>
+ </div>
+ <div class="flex-cell flex-2">
+ <div class="form-group">
+ <input type="text" class="form-control"
+ TODOfocus-me="searchContext.focus_query[idx]"
+ [(ngModel)]="searchContext.query[idx]"
+ (keyup)="checkEnter($event)"
+ placeholder="Query..."/>
+ </div>
+ </div>
+ <div class="flex-cell">
+ <button class="btn btn-sm btn-default"
+ (click)="addSearchRow(idx + 1)">
+ <span class="material-icons">add_circle_outline</span>
+ </button>
+ <button class="btn btn-sm btn-default"
+ [disabled]="searchContext.query.length < 2"
+ (click)="delSearchRow(idx)">
+ <span class="material-icons">remove_circle_outline</span>
+ </button>
+ </div>
+ </div><!-- col -->
+ <div class="col-3">
+ <div *ngIf="idx == 0" class="pull-right">
+ <button class="btn btn-success" type="button"
+ (click)="searchContext.pager.offset=0;searchByForm()">
+ Search
+ </button>
+ <button class="btn btn-warning" type="button"
+ (click)="searchContext.reset()">
+ Clear Form
+ </button>
+ <button class="btn btn-secondary" type="button"
+ *ngIf="!showAdvancedSearch"
+ (click)="showAdvancedSearch=true">
+ More Filters...
+ </button>
+ <button class="btn btn-secondary" type="button"
+ *ngIf="showAdvancedSearch"
+ (click)="showAdvancedSearch=false">
+ Hide Filters
+ </button>
+ </div>
+ </div><!-- row -->
+</div>
+
+ <!--
+ <div class="col-3">
+ <div *ngIf="idx == 0" class="pull-right">
+ <button class="btn btn-success" type="button"
+ ng-click="searchContext.offset=0;searchContext.search_by_form()">
+ [% l('Search') %]
+ </button>
+ <button class="btn btn-warning" type="button"
+ ng-click="searchContext.reset_form()">
+ [% l('Clear Form') %]
+ </button>
+ <button class="btn btn-default" type="button"
+ *ngIf="!showAdvancedSearch"
+ ng-click="showAdvancedSearch=true">
+ [% l('More Filters...') %]
+ </button>
+ <button class="btn btn-default" type="button"
+ *ngIf="showAdvancedSearch"
+ ng-click="showAdvancedSearch=false">
+ [% l('Hide Filters') %]
+ </button>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-9 flex-row">
+ <div class="flex-cell">
+ <eg-org-select nodefault
+ selected="searchContext.searchContext_org">
+ </eg-org-select>
+ </div>
+ <div class="flex-cell flex-3">
+ <select class="form-control" [(ngModel)]="searchContext.sort">
+ <option value=''>[% l('Sort by Relevance') %]</option>
+ <optgroup label="[% l('Sort by Title') %]">
+ <option value='titlesort'>[% l('Title: A to Z') %]</option>
+ <option value='titlesort.descending'>[% l('Title: Z to A') %]</option>
+ </optgroup>
+ <optgroup label="[% l('Sort by Author') %]">
+ <option value='authorsort'>[% l('Author: A to Z') %]</option>
+ <option value='authorsort.descending'>[% l('Author: Z to A') %]</option>
+ </optgroup>
+ <optgroup label="[% l('Sort by Publication Date') %]">
+ <option value='pubdate'>[% l('Date: A to Z') %]</option>
+ <option value='pubdate.descending'>[% l('Date: Z to A') %]</option>
+ </optgroup>
+ <optgroup label="[% l('Sort by Popularity') %]">
+ <option value='popularity'>[% l('Most Popular') %]</option>
+ <option value='poprel'>[% l('Popularity Adjusted Relevance') %]</option>
+ </optgroup>
+ </select>
+ </div>
+ <div class="flex-cell flex-2">
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" [(ngModel)]="searchContext.available"/>
+ [% l('Limit to Available') %]
+ </label>
+ </div>
+ </div>
+ <div class="flex-cell flex-4">
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" [(ngModel)]="searchContext.global"/>
+ [% l('Show Results from All Libraries') %]
+ </label>
+ </div>
+ </div>
+ <div class="flex-cell flex-2">
+ <div *ngIf="searchContext.search_state() == 'searching'">
+ <div class="progress">
+ <div class="progress-bar progress-bar-striped active"
+ role="progressbar" aria-valuenow="100" aria-valuemin="0"
+ aria-valuemax="100" style="width: 100%">
+ <span class="sr-only">[% l('Searching..') %]</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="row pad-vert-min" ng-show="showAdvancedSearch">
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.item_type" multiple="true">
+ <option value=''>[% l('All Item Types') %]</option>
+ <option *ngFor="let item_type of searchContext.ccvm_lists('item_type')"
+ value="{{item_type.code()}}">{{item_type.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.item_form" multiple="true">
+ <option value=''>[% l('All Item Forms') %]</option>
+ <option *ngFor="let item_form of searchContext.ccvm_lists('item_form')"
+ value="{{item_form.code()}}">{{item_form.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.item_lang" multiple="true">
+ <option value=''>[% l('All Languages') %]</option>
+ <option *ngFor="let item_lang of searchContext.ccvm_lists('item_lang')"
+ value="{{item_lang.code()}}">{{item_lang.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.audience" multiple="true">
+ <option value=''>[% l('All Audiences') %]</option>
+ <option *ngFor="let audience of searchContext.ccvm_lists('audience')"
+ value="{{audience.code()}}">{{audience.value()}}</option>
+ </select>
+ </div>
+ </div>
+ <div class="row pad-vert-min" ng-show="showAdvancedSearch">
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.vr_format" multiple="true">
+ <option value=''>[% l('All Video Formats') %]</option>
+ <option *ngFor="let vr_format of searchContext.ccvm_lists('vr_format')"
+ value="{{vr_format.code()}}">{{vr_format.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.bib_level" multiple="true">
+ <option value=''>[% l('All Bib Levels') %]</option>
+ <option *ngFor="let bib_level of searchContext.ccvm_lists('bib_level')"
+ value="{{bib_level.code()}}">{{bib_level.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <select class="form-control" [(ngModel)]="searchContext.lit_form" multiple="true">
+ <option value=''>[% l('All Literary Forms') %]</option>
+ <option *ngFor="let lit_form of searchContext.ccvm_lists('lit_form')"
+ value="{{lit_form.code()}}">{{lit_form.value()}}</option>
+ </select>
+ </div>
+ <div class="col-2">
+ <i>Copy location filter goes here...</i>
+ </div>
+ </div>
+</div>
+-->
+
--- /dev/null
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {EgAuthService} from '@eg/core/auth';
+import {EgOrgService} from '@eg/core/org';
+import {EgCatalogService} from './catalog.service';
+import {SearchContext} from './search-context';
+import {EgIdlObject} from '@eg/core/idl';
+
+@Component({
+ selector: 'eg-catalog-search-form',
+ templateUrl: 'search-form.component.html'
+})
+export class EgCatalogSearchFormComponent implements OnInit {
+
+ searchContext: SearchContext;
+ ccvmMap: {[ccvm:string] : EgIdlObject[]} = {};
+ cmfMap: {[cmf:string] : EgIdlObject[]} = {};
+ showAdvancedSearch: boolean = false;
+
+ constructor(
+ private auth: EgAuthService,
+ private org: EgOrgService,
+ private cat: EgCatalogService
+ ) {}
+
+ ngOnInit() {
+ this.searchContext = this.cat.searchContext;
+ this.ccvmMap = this.cat.ccvmMap;
+ this.cmfMap = this.cat.cmfMap;
+ }
+
+ addSearchRow(index: number): void {
+ this.searchContext.query.splice(index, 0, '');
+ this.searchContext.searchClass.splice(index, 0, 'keyword');
+ this.searchContext.joiner.splice(index, 0, '&&');
+ this.searchContext.match.splice(index, 0, 'contains');
+ }
+
+ delSearchRow(index: number): void {
+ this.searchContext.query.splice(index, 1);
+ this.searchContext.searchClass.splice(index, 1);
+ this.searchContext.joiner.splice(index, 1);
+ this.searchContext.match.splice(index, 1);
+ }
+
+ checkEnter($event: any): void {
+ console.log($event.keyCode);
+ if ($event.keyCode == 13) {
+ this.searchContext.pager.offset = 0;
+ this.searchByForm();
+ }
+ }
+
+ // https://stackoverflow.com/questions/42322968/angular2-dynamic-input-field-lose-focus-when-input-changes
+ trackByIdx(index: any, item: any) {
+ return index;
+ }
+
+ searchByForm(): void {
+ console.log('searchByForm()');
+ this.searchContext.searchOrg = this.org.get(4); // TEST BR1
+ this.cat.search(this.searchContext).then(ok => {
+ console.debug('search complete');
+ });
+
+ }
+
+}
+
+
+++ /dev/null
-
-<h2>Search Sample</h2>
-
-<div *ngIf="context.result">
- <div class="row" *ngFor="let record of context.result.records; let idx = index">
- <div class="col-1">{{idx + 1}}</div>
- <div class="col-3">{{record.title}}</div>
- <div class="col-3">{{record.author}}</div>
- <div class="col-3">{{record.genre}}</div>
- </div>
-</div>
-
+++ /dev/null
-import {Component, OnInit} from '@angular/core';
-import {ActivatedRoute} from '@angular/router';
-import {EgAuthService} from '@eg/core/auth';
-import {EgOrgService} from '@eg/core/org';
-import {EgCatalogService, CatalogContext} from './catalog.service';
-
-@Component({
- templateUrl: 'search.component.html'
-})
-export class EgCatalogSearchComponent implements OnInit {
-
- context: CatalogContext;
-
- constructor(
- private auth: EgAuthService,
- private org: EgOrgService,
- private cat: EgCatalogService
- ) {}
-
- ngOnInit() {
- this.context = new CatalogContext();
-
- this.cat.fetchCcvms().then(ok => { // TODO: catalog resolver
- console.log(this.cat.ccvmMap);
-
- this.context.searchClass = ['keyword'];
- this.context.query = ['piano'];
- this.context.joiner = ['&&'];
- this.context.match = ['contains'];
- this.context.format = null;
- this.context.org = this.org; // hmm, refactor maybe
- this.context.searchOrg = this.org.get(4); // BR1
-
- this.cat.search(this.context).then(ok => {
- console.log('ALL DONE SEARCH');
- });
- });
- }
-}
-
return Observable.create(observer => {
this.auth.testAuthToken().then(
tokenOk => {
+ console.debug('EgStaffResolver: authtoken verified');
this.auth.verifyWorkstation().then(
wsOk => {
this.loadStartupData(observer).then(
},
tokenNotOk => {
// Authtoken is not OK.
+ console.debug('EgStaffResolver: authtoken is not valid');
this.auth.redirectUrl = state.url;
this.router.navigate([this.loginPath]);
- observer.complete();
+ observer.error('invalid auth');
}
);
});
ngOnInit() {
+ console.debug('EgStaffComponent:ngOnInit()');
+
// Fires on all in-app router navigation, but not initial page load.
this.router.events.subscribe(routeEvent => {
if (routeEvent instanceof NavigationEnd) {