-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1980 from genesiscommunitysuccess/pon/framework-i…
…ntegration Draft - Framework integration
- Loading branch information
Showing
3 changed files
with
844 additions
and
3 deletions.
There are no files selected for viewing
387 changes: 387 additions & 0 deletions
387
...op/03_client-capabilities/022_framework-integration/002_integration-angular.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,387 @@ | ||
--- | ||
title: 'Framework integration - Angular' | ||
sidebar_label: 'Angular' | ||
id: client-framework-integration-angular | ||
keywords: [web, integrations, angular] | ||
tags: | ||
- web | ||
- integrations | ||
- angular | ||
sidebar_position: 22 | ||
--- | ||
|
||
|
||
It is easy to set up a new project where your front end uses the Angular framework. | ||
|
||
On this page, we shall show you how to set up an empty project that you can use as a blank canvas for adding Angular and Genesis components. | ||
|
||
These simple steps create an app you log run and log into, and an empty home page. You are then ready to go into the code and add some components. | ||
|
||
We shall also look briefly at: | ||
|
||
- the folder structure of the project | ||
- the principles of routing and styling an application | ||
|
||
:::tip | ||
You can find out more by looking into our [**example application**](https://github.com/genesiscommunitysuccess/howto-ui-integrations-angular/tree/main), where you can look at the code and check the results against the running application. | ||
::: | ||
|
||
## Setting up the Angular project | ||
|
||
:::info prerequisites | ||
Before you start, ensure that you have [Node.js](https://nodejs.org/) and [Genx](../../../development-environment/genx/) installed on your system. | ||
::: | ||
|
||
1. Create a new Angular project. You could use Genesis Create if you prefer. The example below creates a project called **myApp** using Genx with `--framework Angular`: | ||
|
||
|
||
```shell | ||
npx -y @genesislcap/genx@latest init myApp -s blank-app-seed --framework Angular -x | ||
``` | ||
|
||
2. Navigate to your new project's **client** directory: | ||
|
||
```shell | ||
cd ./client | ||
``` | ||
|
||
## Install the dependencies and run the app | ||
|
||
1. Run the following command from your project folder: | ||
|
||
```shell | ||
npm run bootstrap | ||
``` | ||
|
||
2. Start the app in development mode: | ||
|
||
```shell | ||
npm run dev | ||
``` | ||
|
||
The development server launches your project and makes it available on localhost: | ||
|
||
:::note | ||
The project is currently based on Angular 18. | ||
::: | ||
|
||
## Project folder structure and main elements | ||
|
||
### src/main.ts | ||
This is the main entry point for the application. It bootstraps the app by rendering the **app.module.ts** module into the DOM. The file also registers [PBCs](../../../business-components/) using `registerPBCs` | ||
|
||
--- | ||
|
||
### src/pbc | ||
This folder contains components that are responsible for enabling the insertion of slots within the application. | ||
|
||
These slots act as placeholders where content, provided by the registered Project Building Components ([PBCs](../../../business-components/)), is rendered dynamically. The [PBCs](../../../business-components/) are registered in the application through **main.ts**, ensuring that specific components can be inserted into the designated slots at runtime. | ||
|
||
--- | ||
|
||
### src/app/share | ||
The **share** folder holds shared resources and components that are used across the entire application. | ||
|
||
Key files are: | ||
|
||
- **genesis-components.ts**. This registers Genesis framework components, including forms, layouts, and charts. | ||
- **foundation-login.ts**. This configures the foundation-login micro front-end component that handles authorisation and integrates it with the routing system. | ||
|
||
--- | ||
|
||
### src/app/pages | ||
This folder contains the main pages of the application. Each page represents a different route or view, such as the **auth-login.component.ts**, which handles authentication-related flows. | ||
|
||
--- | ||
|
||
### src/app/components | ||
This folder contains reusable UI components that are utilized throughout the app. Components in this folder are not tied to specific pages but are used as building blocks across multiple sections of the application. | ||
|
||
## Routing | ||
|
||
In Angular, routing is essential for creating single-page applications with navigation capabilities. | ||
|
||
The routing configuration in **app/service/route.service.ts** manages and provides routes throughout the application. This file defines a `RouteService` service that combines routes from the main application and additional routes from PBC (Pluggable Business Components). | ||
|
||
The `pbcRoutes` are generated dynamically by mapping over the routes provided by the PBC, extracting essential properties, and wrapping them in a `PBCContainer` component. These routes are then combined with the main application's routes into a single `allRoutes` array. | ||
|
||
The `RoutesProvider` uses Angular's dependency injection to make these routes available to the rest of the application by providing them through the `RoutesService`. | ||
|
||
Additionally, the `RoutesService` is provided to access the routes within Angular components. This ensures seamless integration and accessibility of both main application routes and PBC routes throughout the application. | ||
|
||
## Setting attributes | ||
|
||
Attributes are part of the HTML markup of an element and are reflected in the dom. | ||
|
||
Attributes can be either hard coded or set using the Angular property bindings. Note, Angular automatically maps hyphenated attribute names to camelCase property names so a property called `max-rows` becomes `maxRows`. | ||
|
||
### Text | ||
|
||
To set a text attribute on a component, you can either hard code it in the template or use Angular square bracket template bindings. | ||
|
||
```ts | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-root', | ||
template: ` | ||
<foundation-form | ||
design-system-prefix="rapid" | ||
[resourceName]="resourceName" | ||
></foundation-form> | ||
<!-- or hard code it --> | ||
<foundation-form | ||
design-system-prefix="rapid" | ||
resourceName="EVENT_INSERT_USER" | ||
></foundation-form> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class AppComponent { | ||
resourceName = 'EVENT_INSERT_USER'; | ||
} | ||
``` | ||
|
||
### Boolean | ||
|
||
To set a boolean attribute on a component you can either hard code it in the template or use Angular template bindings `[]`. | ||
|
||
```ts | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-root', | ||
template: ` | ||
<rapid-button [disabled]="isDisabled"> | ||
Disabled button | ||
</rapid-button> | ||
<!-- or hard code it --> | ||
<rapid-button disabled> | ||
Disabled button | ||
</rapid-button> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class AppComponent { | ||
isDisabled = true; | ||
} | ||
``` | ||
|
||
### Number | ||
|
||
To set a text attribute on a component, you can either hard code it in the template or use Angular template bindings `[]`. | ||
|
||
```ts | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-root', | ||
template: ` | ||
<rapid-grid-pro> | ||
<grid-pro-server-side-datasource | ||
resource-name="ALL_TRADES" | ||
[maxRows]="maxRows" | ||
></grid-pro-server-side-datasource> | ||
</rapid-grid-pro> | ||
<!-- or hard code it --> | ||
<rapid-grid-pro> | ||
<grid-pro-server-side-datasource | ||
resource-name="ALL_TRADES" | ||
max-rows="100" | ||
></grid-pro-server-side-datasource> | ||
</rapid-grid-pro> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class AppComponent { | ||
maxRows = 100; | ||
} | ||
``` | ||
|
||
## Setting properties | ||
|
||
Properties are part of the Javascript object representation of the DOM element. They are used for dynamic interaction and setting complex non-primitive data types such as objects and arrays. | ||
|
||
You can set these using Angular template bindings `[]`. | ||
|
||
```ts | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-root', | ||
template: ` | ||
<foundation-form | ||
design-system-prefix="rapid" | ||
[jsonSchema]="jsonSchema" | ||
></foundation-form> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class AppComponent { | ||
jsonSchema = { | ||
type: 'object', | ||
properties: { | ||
QUANTITY: { | ||
type: 'number', | ||
description: 'kotlin.Double', | ||
}, | ||
SIDE: { | ||
type: 'string', | ||
description: 'kotlin.String', | ||
}, | ||
}, | ||
}; | ||
} | ||
``` | ||
|
||
## Handling events | ||
|
||
You can handle events from Foundation UI components using Angular's event binding `()`. | ||
|
||
```ts | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-root', | ||
template: ` | ||
<foundation-form | ||
(submit)="handleSubmit($event)" | ||
></foundation-form> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class AppComponent { | ||
handleEvent(e): void { | ||
console.log('form submitted', e); | ||
} | ||
} | ||
``` | ||
|
||
## Styling the application | ||
|
||
### Global styles | ||
You can add global styles by modifying the main stylesheet located at **src/styles/styles.css**. This file contains styles that apply to the entire application. | ||
|
||
--- | ||
|
||
## Slots | ||
|
||
Many components in FoundationUI have slots which act as placeholders to allow you to fill components with your own markup. | ||
|
||
This is equivalent to [content projection](https://angular.dev/guide/components/content-projection) in Angular. | ||
|
||
This example shows how you can use the slots in the Modal component | ||
|
||
```typescript | ||
import { AfterViewInit, Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, ViewChild } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'modal-example', | ||
template: ` | ||
<rapid-button (click)="showModal()">Show modal</rapid-button> | ||
<rapid-modal #modal | ||
> | ||
<h3 slot="top">Top slot</h3> | ||
Main content in the modal | ||
<div slot="bottom"> | ||
<i>Slotted content in the bottom</i> | ||
</div> | ||
</rapid-modal> | ||
`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class ModalExampleComponent implements AfterViewInit { | ||
@ViewChild('modal') modalRef!: ElementRef; | ||
|
||
showModal() { | ||
if (this.modalRef.nativeElement) { | ||
this.modalRef.nativeElement.show() | ||
} | ||
} | ||
|
||
} | ||
``` | ||
|
||
## Dependency Injection | ||
|
||
Foundation UI has a suite of services that can be added to your application via dependency injection. | ||
|
||
For example, if you want to use the Connect service, the best approach is to create an injection token and register it in your app module. | ||
|
||
:::info | ||
You can follow this same procedure for any other service from the framework that works via dependency injection. | ||
::: | ||
|
||
**connect-service.ts** | ||
|
||
```ts | ||
import { Connect, getConnect } from '@genesislcap/foundation-comms'; | ||
import { InjectionToken } from '@angular/core'; | ||
|
||
export const connectService = getConnect(); | ||
export const CONNECT_TOKEN = new InjectionToken<Connect>('Logger'); | ||
``` | ||
|
||
**app.module.ts** | ||
```ts | ||
@NgModule({ | ||
... | ||
providers: [ | ||
{ provide: CONNECT_TOKEN, useValue: connectService }, | ||
... | ||
], | ||
... | ||
}) | ||
``` | ||
|
||
**your-angular-component.ts** | ||
|
||
After adding the connect service to your module providers using an injection token, you can add it to any class using Angular DI. | ||
|
||
This component will use the Connect `snapshot` method to retrieve data from a dataserver query `ALL_TRADES` and render it in a list. | ||
|
||
```typescript | ||
import { OnInit, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | ||
import { NgForOf } from '@angular/common'; | ||
import { Connect } from '@genesislcap/foundation-comms'; | ||
import { CONNECT_TOKEN } from 'path/to/connect.service'; | ||
|
||
@Component({ | ||
selector: 'di-example', | ||
template: ` | ||
<ul> | ||
<li *ngFor="let item of data">Direction: {{item.TRADE_ID}} Quantity: {{item.QUANTITY}} Ticker: {{item.TICKER}}</li> | ||
</ul>`, | ||
standalone: true, | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
imports: [ NgForOf ], | ||
|
||
}) | ||
export class DIExampleComponent implements OnInit { | ||
constructor(@Inject(CONNECT_TOKEN) private connect: Connect) {} | ||
|
||
async ngOnInit() { | ||
const response = await this.connect.snapshot('ALL_TRADES') | ||
|
||
if (response.ROW?.length) { | ||
this.data = response.ROW; | ||
} | ||
} | ||
} | ||
``` | ||
|
||
### Design tokens | ||
|
||
Design tokens are declared in the **src/styles/design-tokens.json** file. They offer an effective way to manage and apply styles in your application in a consistent and maintainable manner. | ||
|
||
The design tokens enable you to define and manage values such as colours, fonts, and spacing across the whole application. You can modify these tokens to propagate changes wherever they are used in the application. | ||
|
||
:::note | ||
See more details in our page on [Design systems](../../../design-systems/introduction/) | ||
::: |
Oops, something went wrong.