novichkov-lab / generix-ui

0 stars 3 forks source link

Generix UI

This is the user facing portion of the Generix Data Clearinghouse. It is designed to simplify tasks on our system that can be challenging for data producers and data consumers alike.

Installation

to get started, make sure you have npm and Angular installed. This app is built with Angular version 7.2.5.

npm install -g @angular/cli

Fork and clone a repo and then install all the necessary dependencies in package.json.

npm install

If you run into dependency problems you can't resolve, try installing an older version of @angular/cli. This app has been successfully deployed with Angular versions 7.2.5 and 7.2.15.

To run a development server, use the ng serve command and open your preferred browser to localhost:4200

Deployment

Once you are logged into the server, you can find a clone of the repository at /home/clearinghouse/env/generix-ui/generix-ui. Pull your changes and run the following build command:

npm install

sudo ng build --prod --base-href /generix-ui/

The build target directory is configured in angular.json to default to /var/www/html/generix-ui/. In order for the resources to be loaded correctly, the base href needs to be set to /generix-ui/. This can either be done with the --base-href flag as demonstrated above or you can manually change it in the index.html generated by the build command.

Note that everything in the build target directory will be deleted!

The --prod directive above configures the UI with the "prod" environment, which is configured via src/environments/environment.prod.ts

If there is not an .htaccess file in the build target directory, a new one will need to be generated for the page to load. paste the following code below in a new .htaccess file at /var/www/html/generix-ui/:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
  RewriteRule ^ - [L]

  RewriteRule ^ index.html
</IfModule>

Overview

generix-ui is structured into modules that pertain to the part of the site the user is visiting. The following diagram is a high level overview of the structure of the app.

app.module
|__ search.module
|   |__ search components
|__ upload.module
|   |__ upload components
|__ plot.module
|    |__ plot components
|__ shared folder
    |__ components
    |__ services
    |__ directives
    |__ models
    |__ pipes

jQuery is installed in order to support custom UI element plugins, namely DataTables and Select2

DataTables

DataTables is used for rendering HTML tables with javascript to add search, filtering, and pagination to large tables. DataTables is currently implemented in generix-ui wihout an angular wrapper, so $ will need to be imported from jQuery in order to render a table as a DataTable. It is best to render a table in the AfterViewInit lifecycle hook with an ElementRef provided by angular as shown below:

import { ElementRef, ViewChild } from '@angular/core';
import * as $ from 'jquery';
import 'datatables.net';
import 'datatables.net-bs4'; // for bootstrap 4 styles
...
export class SomeComponent implements afterViewInit {
    @ViewChild('table') private el: ElementRef;
    dataTable: any;

    ngAfterViewInit() {
        this.someService.getSomeData().subscribe(data => {
            // assign data to table
            const table: any = $(this.el.nativeElement);
            this.dataTable = table.DataTable();
        });
    }
}

Select2

Select2 is used to create comboboxes that populate with data from our system. It is configured to work with angular using ng2-select2. Select2 elements can be rendered using a <select2> tag and take an input of options and data, where data is the data with will populate the dropdown and options take the congiguration for the dropdown. The cssImport input is necessary for select2 to add styles. User selection can be handled using the (valueChanged) event handler.


<select2
    [data]="data"
    [options]="options"
    [cssImport]="true"
    [value]="selectedValue"
    (valueChanged)="setValue($event)"
</select2>
>

import { Select2OptionData } from 'ng2-select2';

@Component({...})

export class ComponentWithSelect2 implements OnInit {

    selectedValue = '0';

    // typical select 2 options config
    public options: Select2Options = {
        width: '100%' // width is calculated here
        containerCssClass: 'select2-custom-container'
        // ^ class defined in styles.css, ensures consistent UI with the rest of app
        placeholder: 'placeholders can be put here'
        // placeholders only work if there is an empty data element in the data file
        query: (options: Select2QueryOptions) => {
            // this is the option used to get data asynchronously based on user search term
            const text = options.term;
            this.someService.getSomeData().subscribe((res: any) => {
                options.callback(res.results);
            })
        }
    }

    public data: Select2OptionData[] = [
        {id: '', text: ''}, // necessary to create placeholders and non default selections
        {id: '0', text: 'value that the user sees'}
    ];
}

Important things to note about Select2:

Bootstrap 4 and Ngx-Bootstrap

for CSS UI, Bootstrap 4 is used along with ngx-bootstrap for advanced javascript features (e.g modals and tooltips).