Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this example, we create a custom state that shows a chart with an overview of all objects in the system. The resulting doughnut chart is clickable to drill down into the specific object types.

Image RemovedImage Removed

Implementation

  1. Use a CLI command to generate a state component with a custom name and sidebar link. The link appears in the navigation menu on the left. (sidebar-navigation = default)

    Code Block
    languagebash
    linenumberstrue
    eo g state custom


  2. Use a CLI command to install the maps package (takes some time).

    Code Block
    languagebash
    linenumberstrue
    npm install -P ng2-charts@1.6.0


  3. Import ChartsModule module to CustomStatesModule.

    Code Block
    languagejs
    titlecustom-states.module.ts
    linenumberstrue
    import {NgModule} from '@angular/core';
    import {CommonModule} from '@angular/common';
    import {Route, RouterModule} from '@angular/router';
    import {EoFrameworkModule} from '@eo-sdk/client';
    import {EoLinkPlugin} from '@eo-sdk/client';
    import {AuthGuard} from '@eo-sdk/client';
    import {CustomComponent} from './custom/custom.component';
    import {ChartsModule} from 'ng2-charts';
    
    export const routes: Route[] = [
      {path: CustomComponent.path, component: CustomComponent, canActivate: [AuthGuard]},
    ];
    
    export const links: EoLinkPlugin[] = [
      CustomComponent
    ];
    
    @NgModule({
      imports: [
        CommonModule,
        EoFrameworkModule,
        RouterModule.forChild(routes),
        ChartsModule
      ],
      declarations: [CustomComponent]
    })
    export class CustomStatesModule {
    }


  4. Update custom.component.ts to load current chart data.

    Code Block
    languagejs
    titlecustom.component.ts
    linenumberstrue
    import {Component, ViewChild} from '@angular/core';
    import {Chart} from 'chart.js';
    import {TranslateService, SearchService} from '@eo-sdk/core';
    import {BaseChartDirective} from 'ng2-charts';
    import {AppSearchService, UnsubscribeOnDestroy} from '@eo-sdk/client';
    import {takeUntil} from 'rxjs/operators';
    
    @Component({
      selector: 'eo-custom',
      templateUrl: './custom.component.html',
      styleUrls: ['./custom.component.scss']
    })
    export class CustomComponent extends UnsubscribeOnDestroy {
    
      static id = 'eo.custom.state.custom';
      static path = 'custom/custom';
      static matchType = new RegExp('sidebar-navigation');
    
      groupCount: number;
      totalCount: number;
      chart;
      activeType = 0;
      types = [];
    
      @ViewChild(BaseChartDirective) chartEl: BaseChartDirective;
    
      constructor(private translate: TranslateService,
                  private searchService: SearchService,
                  private appSearchService: AppSearchService) {
        super();
        this.fetchData();
      }
    
      chartClicked(el?) {
        if (!el || (this.activeType === this.groupCount && el.active[0])) {
          this.activeType = el ? el.active[0]._index : this.groupCount;
          this.chart = this.dataToChart(this.types[this.activeType]);
          setTimeout(() => {
            this.chartEl.chart.config.data.labels = this.chart.labels;
            this.chartEl.chart.update();
          }, 0);
        }
      }
    
      dataToChart(groups: any[]): Chart {
        return {
          data: [{
            data: groups.map(g => g.count),
            label: ''
          }],
          labels: groups.map(g => g.label)
        };
      }
    
    
      private fetchData() {
        this.appSearchService.setTerm('');
        this.appSearchService
          .queryState$
          .pipe(
            takeUntil(this.componentDestroyed$)
          )
          .subscribe(res => {
              this.totalCount = res.count;
              this.groupCount = this.appSearchService.objectTypeGroups.length;
              this.types = [];
    
              const main = this.appSearchService.objectTypeGroups.map((g) => {
                const type = g.types.map(t => ({label: t.label, count: res.aggregations.type.get(t.qname) || 0}));
                this.types.push(type.sort((a, b) => b.count - a.count));
                return {
                  label: g.label === '0' ? this.translate.instant('eo.quicksearch.result.group.global') : g.label,
                  count: type.map(t => t.count).reduce((a, b) => a + b, 0)
                };
              });
    
              this.types.push(main.sort((a, b) => b.count - a.count));
              this.chartClicked();
            }
          );
      }
    }
    


  5. Update custom-state.component.html to include a chart component.

    Code Block
    languagexml
    titlecustom-state.component.html
    linenumberstrue
    <button class="summary" (click)="chartClicked()">
      <span class="label" *ngIf="activeType != groupCount">{{types[groupCount][activeType].label}}: &nbsp;</span>
      <span class="count" *ngIf="activeType != groupCount"> {{types[groupCount][activeType].count}} of &nbsp;</span>
      <span class="total">{{totalCount}}</span>
    </button>
    
    <div class="chart-container">
      <canvas baseChart *ngIf="chart" height="100%"
              [datasets]="chart.data"
              [labels]="chart.labels"
              [chartType]="'doughnut'"
              (chartClick)="chartClicked($event)"></canvas>
    </div>


  6. To finish this state, add some styling

    Code Block
    languagecss
    titlecustom-state.component.scss
    linenumberstrue
    :host {
      flex: 1;
      display: flex;
      flex-flow: column;
    
      .summary {
        align-items: baseline;
        position: absolute;
        right: 30px;
        top: 30px;
        flex: 1 1 auto;
        display: flex;
        background: papayawhip;
        border-radius: 4px;
        padding: 16px;
        border: 1px solid rgba(255, 255, 255, 0.2);
    
        .label {
          font-size: 1.5em;
        }
        .count {
          font-size: 2.5em;
        }
        .total {
          font-size: 3.5em;
        }
    
      }
      .chart-container {
        flex: 0 0 auto;
      }
    }


  7. Use a CLI command to generate labels/translations.

    Code Block
    languagebash
    linenumberstrue
    eo g label eo.custom.state.custom --en "Custom state" --de "Custom state"


...

This example provides two new states. The first one shows the search result list in full screen, outside the usual client context. The second one shows the content preview of an object, also in full screen.Image RemovedImage RemovedImage Removed

Implementation

...

In this example, we add a new custom action that opens an image gallery.Image RemovedImage Removed

Implementation

...