-
Notifications
You must be signed in to change notification settings - Fork 0
Frontend Angular en
- Download Node.js. Download and installation from: https://nodejs.org/en/
- npm - Package Manager (is available after the installation of node on the command line)
-
Angular/cli. Installation from command line:
npm install -g @angular/cli
-
Json-server. From command line:
npm install -g json-server
-
IDE's, that work with Angular:
Visual Studio Code
Atom
Webstorm
ng new test-app
cd test-app
ng serve
- The Frontend is accessible on: http://localhost:4200
-
The Angular client is a practical tool to create new components, services etc. easily.
-
You can install the Angular client globally on the computer with:
-
npm install -g @angular/cli
-
These are some examples for the most important classes in Angular:
-
Create a service
ng generate service hospital
-
Create a component
ng generate component hospital
-
Create a model
ng generate class hospital --type=model
-
Create a module
ng genarate module hospital
- This documentation shows a good overview: https://angular.io/docs
The basic blocks of an Angular application are the NgModules, which contain the complication context for the components. The NgModules merge related code into functional sets. The complete application is then a combination of NgModules. Every Angular application has at least one module, the root module, which enables bootstrapping. Typically there are many more modules available.
- In spite we don't have a lot of different components and services we just need the app-module and didn't create more modules. But we have also predefined modules, which we use in the project.
- Our app-module is set up like this:
import {environment} from "../environments/environment";
import {HttpClientModule} from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, ApplicationRef } from '@angular/core';
import { FormsModule} from '@angular/forms';
import { CommonModule } from '@angular/common';
import {AppRoutingModule} from "./app-routing.module";
import { AppComponent } from './app.component';
import { MapsComponent } from './components/maps/maps.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { HospitalComponent } from './components/hospital/hospital.component';
import { DropdownComponent } from './components/dropdown/dropdown.component';
import { CharacteristicsComponent } from './components/characteristics/characteristics.component';
import {CharacteristicsService} from './services/characteristics.service';
import {HospitalService} from "./services/hospital.service";
@NgModule({
declarations: [
AppComponent,
MapsComponent,
NavbarComponent,
HospitalComponent,
DropdownComponent,
CharacteristicsComponent
],
imports: [
BrowserModule,
HttpClientModule,
CommonModule,
FormsModule,
AppRoutingModule,
],
providers: [
CharacteristicsService,
HospitalService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
- The models are used to define the data model for the data we use
- In the models we define what type our attributes have (like numbers, strings, etc.)
- It would be also possible to use interfaces instead
- The following code shows our hospital model
export class Hospital {
_id: String;
name: String;
streetAndNumber: String;
plzAndCity: String;
latitude: String;
longitude: String;
//attributes: any[];
hospital_attributes: {
value: String;
year: number;
code: String;
}
hospital_locations: {
name: String;
streetAndNumber: String;
plzAndCity: String;
latitude: String;
longitude: String;
la: String;
kanton: String;
}
constructor(){
this.name = "";
this.streetAndNumber = "";
this.plzAndCity = "";
this.latitude = "";
this.longitude = "";
this.hospital_attributes = { code: "", value: "", year: 0};
this.hospital_locations = {name: "", streetAndNumber: "", plzAndCity: "", latitude: "", longitude: "", la: "", kanton: ""}
}
}
- The data is loaded with services and is used after that in the associated components
- The services are used to provide program logic that is used in different components
- All the logic that is not in direct context with the view is outsourced in services
- To retrieve the data in the service from the backend, the HttpClient is used, which accesses the desired URL's, where the JSONs are located
import { HttpClient, HttpHeaders } from '@angular/common/http';
constructor(private http: HttpClient) {
}
- In the hospital services we get the hospitals with all corresponding data (addresses, coordinates, attributes)
- This shows the way how to access the backend with heroku
/**
* Gets all hospitals with all corresponding data (address, coordinates, attributes)
* @returns {Observable<Hospital[]>} data in form of the defined model Hospital
*/
getAll(): Observable<Hospital[]> {
return this.http.get<Hospital[]>('https://geopital.herokuapp.com/' + 'api/hospitals')
.map(res => {
return res as Hospital[]
})
}
- When you want to access the backend locally with the localhost you have to call this api
/**
* Gets all hospitals with all corresponding data (address, coordinates, attributes)
* @returns {Observable<Hospital[]>} data in form of the defined model Hospital
*/
getAll(): Observable<Hospital[]> {
return this.http.get<Hospital[]>('http://localhost:3000/' + 'api/hospitals')
.map(res => {
return res as Hospital[]
})
}
- In the characteristics service we load the numeric and the categorical attributes separated, to use them for the attribute selection
- The numerical attributes determine the size of the points
- The categorical attributes determine if the hospitals are displayed at all
- Further processing is happening in the dropdown component
- This shows again the way to access it with heroku
/**
* Gets all attributes which a hospital can have
* @returns {Observable<Attributes[]>} data in form of the defined model Attributes
*/
getCategoricalAttributes(): Observable<Attributes[]> {
return this.http.get<Attributes[]>('https://geopital.herokuapp.com/' + 'api/attributeTypes')
.map(res => {
return res['attribute_types_string'] as Attributes[];
})
}
getNumericalAttributes(): Observable<Attributes[]> {
return this.http.get<Attributes[]>('https://geopital.herokuapp.com/' + 'api/attributeTypes')
.map(res => {
return res['attribute_types_number'] as Attributes[];
})
}
- And this is the way to access it through the localhost
/**
* Gets all attributes which a hospital can have
* @returns {Observable<Attributes[]>} data in form of the defined model Attributes
*/
getCategoricalAttributes(): Observable<Attributes[]> {
return this.http.get<Attributes[]>('http://localhost:3000/' + 'api/attributeTypes')
.map(res => {
return res['attribute_types_string'] as Attributes[];
})
}
getNumericalAttributes(): Observable<Attributes[]> {
return this.http.get<Attributes[]>('http://localhost:3000/' + 'api/attributeTypes')
.map(res => {
return res['attribute_types_number'] as Attributes[];
})
}
- In the components we have all logic implemented, which is in direct context to the view
- A component includes a typescript, a HTML and a CSS file
- TypeScript: For the logic
- HTML: For the view
- CSS: For the design
- The dropdown component is the middle part of the menu on the right side
- In the dropdown component, the numerical and categorical variables are processed further and loaded into the selection field on the right side of the screen
/**
* Is called on init and loads the attribute-array from the backend.
* The attributes are stored in two arrays, one that contains all the
* numerical and the other that contains all categorical attributes
* The attributes are then displayed in the html.
*/
ngOnInit() {
this.characteristicsService.getCategoricalAttributes()
.subscribe(attributes => {
this.categoricalAttributes = attributes;
});
this.characteristicsService.getNumericalAttributes()
.subscribe(attributes => {
this.numericalAttributes = attributes;
});
}
- The data is then loaded in HTML in this way (example for the categorical attributes)
<!-- first dropdown with categorical attributes -->
<div id="numAttr" class="dropdown" style="padding:5px;">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
1. Attribut:
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" *ngFor="let attribute of categoricalAttributes"
(click)="selectedNumAttribute(attribute)">{{ attribute.nameDE }}</a>
</div>
</div>
- The navbar component is the upper field in the menu on the right side
- There the hospital types can be selected
- This navbar also acts as a legend which color applies to which type of hospital
- The following example shows the code for selecting the University Hospital (the further logic is done in MapInitializer, see documentation Frontend D3)
/** NavbarComponent.ts */
if (hospitalType == 'K111') {
this.numUniSp = this.numUniSp+1;
updateMap(this.numUniSp, this.numZentSp, this.numGrundVers, this.numPsychKl, this.numRehaKl, this.numSpezKl);
}
<!-- NavbarComponent.html -->
<label class="container">Universitätsspitäler
<input type="checkbox" checked="checked" (change)="selectHospitalType('K111')">
<span class="checkmark1"></span>
</label>
/* NavbarComponent.css */
.checkmark1 {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
background-color:#a82a2a;
}
- The categorical attributes component lists all these attributes
- It defines the view for the sidebar menu
// all categorical codes
private CatCodeList = ["RForm", "Akt", "SL", "WB", "SA", "LA"];
// default category to show on loaded site
private DefaultCategory = {code:"RForm", nameDE:"Rechtsform", nameFR: "Forme juridique", nameIT: "Forma giuridica"}
// dictionaries with all options of the categorical codes,
// when an option is true it's selected, when false it's deselected
RformDict = {'R1':true, 'R2':true, 'R3':true, 'R4':true};
AktDict = {'A':true, 'B':true, 'P':true, 'R':true};
SLDict = {'IPS':true, 'NF':true};
WBDict = {'Arzt':true, 'BGs':true, 'MSt':true};
SADict = {'Angio':true, 'CC':true, 'CT':true, 'Dia':true,
'LB':true, 'Lito':true, 'MRI':true, 'PET':true};
LADict = {'Stat':true, 'Amb':true};
allDict = {'RForm':this.RformDict,
'Akt':this.AktDict,
'SL':this.SLDict,
'WB':this.WBDict,
'SA':this.SADict,
'LA':this.LADict};
- As an example from the HTML, the RForm (Rechtsform)
<div id="RForm">
<fieldset>
<div class="wrapper">
<label class="container"> R1: AG / GmbH
<input type="checkbox" name="checkbox" checked="checked" (change)="selectedCatValue('RForm','R1')">
<span class="checkmark1"></span>
</label>
<label class="container"> R2: Verein / Stiftung
<input type="checkbox" name="checkbox" checked="checked" (change)="selectedCatValue('RForm','R2')">
<span class="checkmark1"></span>
</label>
<label class="container"> R3: Einzelfirma / Gesellschaft
<input type="checkbox" name="checkbox" checked="checked" (change)="selectedCatValue('RForm','R3')">
<span class="checkmark1"></span>
</label>
<label class="container"> R4: Öffentliches Unternehmen
<input type="checkbox" name="checkbox" checked="checked" (change)="selectedCatValue('RForm','R4')">
<span class="checkmark1"></span>
</label>
</div>
</fieldset>
</div>
- The characteristics component is for the characteristics of the clicked hospitals
- The logic is happening in the 'mapinitalizer.js'. but the view is defined here
<div class="nav-bar-characteristics">
<nav id="char-container" class="navbar navbar-expand-lg navbar-dark bg-light">
<div id="characteristics">
<h5 id="hospitalName"></h5>
<div class="table-wrapper">
<table class="table table-responsive-md">
<thead class="mdb-color lighten-4">
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Adresse:</td>
<td id="hospitalAddress"></td>
</tr>
<tr>
<td id="numericalAttributeName"></td>
<td id="numericalAttributeValue"></td>
</tr>
<tr>
<td id="categoricalAttributeName"></td>
<td id="categoricalAttributeValue"></td>
</tr>
</tbody>
</table>
</div>
</div>
</nav>
</div>
- In the Map Component the getAll() function of the Hospital Service is called to load the hospitals with all attributes
- In addition, the Characteristics Service loads the numerical attributes to determine the size of the points on the map. By default, we take the income from medical services provided by the respective hospitals
/**
* Loads all hospital data from backend with the help of hospitalService
* and gives it to the mapDrawer() function in mapInitializer.js
*/
ngOnInit() {
this.characteristicsService.getNumericalAttributes()
.subscribe(x => {
this.numericalAttributes = x;
this.characteristicsService.getCategoricalAttributes()
.subscribe(y => {
this.categoricalAttributes = y;
this.hospitalService.getAll()
.subscribe(hospitals => {
this.hospitalsList = hospitals;
mapDrawer(this.hospitalsList, this.numericalAttributes, this.categoricalAttributes);
});
})
});
}
- MapComponent.html initializes the map created in MapInitializer.js
<!-- show map defined in mapInitializer.js on screen -->
<div id="mapid" style="width: 100%; height: 100%; position: absolute"></div>
- In addition, in MapComponent.html all components are called, which are then displayed on the map
<!-- shows navbar on the map -->
<app-navbar></app-navbar>
<!-- shows dropdown on the map -->
<app-dropdown></app-dropdown>
<!-- shows the characteristics on the map -->
<app-characteristics></app-characteristics>
- The visualization part is explained in the Frontend D3 documentation: https://github.com/eonum/geopitalsuisse/wiki/Frontend-D3
Ohne Dokumentation wären wir alle Tiere.