Technical Articles
Create your first Fundamental Library Application
In this blog post, you will learn how to create your first application using Fundamental Library – more specifically with Fundamental Library for Angular and Fundamental Library Styles). You can also use a working variant of the application can be found here.
We will use a few components(mainly button
and alert
), which should it will look like this:
You would be able to trigger different alerts
by clicking on the buttons
.
Prerequisites
- NPM – node package manager. Here’s more information how to install it.
- Angular – a TypeScript-based open-source web application framework
- Angular CLI – A command line interface for Angular. Here’s more information how to install the CLI.
- IDE by choice. We will be using Visual Studio Code.
Create your First Angular Application
We will be using Angular CLI command line interface to create a new angular application from scratch.
The first step is to decide where you want to create the application and open a terminal into that directory. Let’s create a new application my-cool-ngx-app
with the command:
ng new my-cool-ngx-app
Then, we go in the folder of the newly created application and run it:
cd my-cool-ngx-app
ng serve
You can test whether the application is properly running by opening a browser tab at http://localhost:4200/
, which should look like this:
We will delete the content of the generated application:
- Open the application with your IDE. The folder structure will look similar to:
- Open and delete the content of the file
app.component.html
and save it
Bring Fundamental Libraries
In the previous section, we created a new Angular application with Angular CLI, we ran and tested it. We also deleted the template content generated with the CLI.
In this section, we will focus on bringing Fundamental Library for Angular. This will require very few steps:
Go to the folder of the application in your terminal and run the command:
ng add @fundamental-ngx/core
It will ask you to add an Animation, choose Y
:
This will do a few things:
- Add
@fundamental-ngx/core
package to your direct dependencies into yourpackage.json
and it will install it. - Add path of icon font and 72 font files into
angular.json
styles property. This will include those files as the published assets, so the application can use them.
Create the Application
The only thing you need to do now is to import and use components from Fundamental Library for Angular (Core). Let’s import modules for alert
and button
in app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {
ButtonModule,
AlertModule
} from '@fundamental-ngx/core';
import { AppComponent } from './app.component';
import {
BrowserAnimationsModule
} from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent
],
imports: [
AlertModule,
ButtonModule,
BrowserModule,
BrowserAnimationsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
We can now add some content of the application in app.component.html
:
<div class="wrapper">
<button fd-button
[glyph]="'action'"
(click)="openFromComponent()">Opeb from Component</button>
<button fd-button
[glyph]="'action'"
(click)="openFromTemplate(template)">Open from Template</button>
<button fd-button
[glyph]="'action'"
(click)="openFromString()">Open from String</button>
<button fd-button
[glyph]="'sys-cancel'"
[options]="'emphasized'"
(click)="alertService.dismissAll()"
[disabled]="!alertService.hasOpenAlerts()">Dismiss All</button>
<button fd-button
[glyph]="'palette'"
(click)="toggle()">Change Theme</button>
</div>
<!-- Defining a template to open -->
<ng-template let-alert #template>
<div>{{alert.data.firstLine}}</div>
<div>{{alert.data.secondLine}}</div>
<button fd-button
[fdType]="'positive'"
[options]="'emphasized'"
[compact]="true"
(click)="alert.dismiss('Data passed back')">
Click to dismiss
</button>
</ng-template>
We are using a few buttons that will trigger different types of alert
(component
, template
, string
) and one more button for switching the themes. For that reason, we will create a new file alert-example.component.ts
, which will be used to be opened as an alert
content:
import { Component } from '@angular/core';
import { AlertRef } from '@fundamental-ngx/core';
@Component({
selector: 'fd-alert-content',
template: `
<div>{{ref.data.label}}</div>
<div>It will stay open when the mouse is hovered inside.</div>
<div>Injecting AlertRef allows you to call
<code>dismiss()</code>
on the alert or access passed data.</div>
`
})
export class AlertContentComponent {
constructor(public ref: AlertRef) {}
}
We are using data that can be passed from the component triggering the alert
. In our example this is the property label
.
As a last step, we will add some logic in app.component.ts
:
import { Component } from '@angular/core';
import { AlertContentComponent } from './alert-content.component';
import { AlertService } from '@fundamental-ngx/core';
@Component({
selector: 'fd-alert-component-as-content-example',
templateUrl: './alert-component-as-content-example.component.html',
styleUrls: ['alert-component-as-content-example.component.scss']
})
export class AlertComponentAsContentExampleComponent {
constructor(public alertService: AlertService) { }
openFromComponent() {
this.alertService.open(AlertContentComponent, {
type: 'warning',
minWidth: '500px',
mousePersist: true,
duration: 7500,
data: {
label: 'This alert was opened by providing a component as content!'
}
});
}
openFromString() {
const alertContent = 'This is the content! The alert is not dismissible, but will disappear after 7500ms.';
this.alertService.open(alertContent, {
type: 'information',
minWidth: '500px',
dismissible: false,
duration: 7500
});
}
toggle(){}
openFromTemplate(template): void {
const alertRef = this.alertService.open(template, {
type: 'success',
duration: -1,
minWidth: '500px',
data: {
firstLine: 'This alert passes data to the template.',
secondLine: 'It also has [duration]="-1" and will not disappear automatically.'
}
});
alertRef.afterDismissed.subscribe((data) => {
// Do something after closing, receive data
// You can also manually close this alert using alertRef.dismiss()
});
}
}
The final version of app.module.ts
should look like this:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {
ButtonModule,
AlertModule
} from '@fundamental-ngx/core';
import { AlertExampleComponent } from './alert-example.component'
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
declarations: [
AppComponent,
AlertExampleComponent
],
imports: [
AlertModule,
ButtonModule,
BrowserModule,
BrowserAnimationsModule
],
providers: [],
bootstrap: [AppComponent],
entryComponents:[AlertExampleComponent]
})
export class AppModule { }
The goal of this blog post was to introduce some of the packages from Fundamental Library
.
Check out the other blog posts related to Fundamental Library
.
Hi Mladen,
I'm still kind of missing the big picture, how such an application (be it angular, vue, or whatever works with HTML-elements) might / should play together with the gateway.
Guidlines on OData models & client libraries, "smart" forms / tables, ...
Or how that might be integrated into the FLP?
Any ressources or plans on that, you might be allowed to share?
Kind Regards
Dominik
Hi Dominik Augustin,
Your questions are valid ones and we are considering this seriously. One direction we are exploring is using metaUI and luigi. If you have ideas or suggestions, feel free to share. We are open for a discussion.
We have applications that are not on top of OData yet but still have to be consistent with Fiori.
best regards,
Mladen
Hi Dominik Augustin
One part of this are UI components, how we render this or that, and another side is how we represent our state on the UI, how we connect to our micro-services, how we cache data on the client side, etc..
Let's separate those two.
We do have more requirements that works with REST API and there is a harmonization in progress to make Rest API and OData compatible with respect to features. According to the SAP Technological Guidelines.
There is also another stream to introduce StateManagement layer and it is designed in such way that you would be able to provide your own implementation if needed. Not only rest, but maybe graphQL or even OData. But default is going to be REST.
Thanks,
Frank
Hi Mladen,
My question goes into a similar direction as Dominik's: What about using the SAP UI5 theme designer in order to style also apps using one of the SAP Fundamental libraries?
My background is not so much in building S/4-hosted UI5 apps, but I'm mainly building side-by-side extensions. However, in order to be able to use both e.g. SAP Fiori Element based apps and fundamental-ngx based ones in one and the same system landscape, having a common theme (even if not 100% matching, but good enough) is a must-have from my point of view.
Is there already a way to achieve this?
Thanks and kind regards,
Valentin
Hi Valentin,
Thank you for your question.
The components in fundamental library are using the theme designer’s theming parameters(css variables). So if your application is connected with the theming services and you get custom theming parameters then your application based on fundamental-ngx will be restyled. We have an internal demo where we included 2 applications(a ui5 demo app and a fundamental-ngx application under luigi) and when the user changes the theme through the shellbar both applications get re-themed.
cheers,
Mladen
Hi Mladen,
the library looks very good but often I find the documentation a bit lacking especially when one is not familiar with the Fiori Design guidelines.
For example, the Combo Box component documentation does not show how to change the matching strategy.
Recently the default strategy in the library has changed from 'contains' to 'starts with'.
Likely because 'starts with' is closer to the default in Fiori which is 'starts with element'?
Unfortunately the documentation doesn't show how to change this strategy.
So from my point of view up until version 0.24 I had a nicely working combobox that behaves in one way but on version 0.27 the combobox has changed and the documentation does not show how to change the behaviour back.
Would be nice to have a forum where one could post questions like this about the components where the documentation may be lacking.
(By the way, if you know how to change the default matching strategy for the Combo Box component, I'd love to see it!)
hi Alfonso Armenta,
thank you for the feedback! We are working hard on the documentation and the plan is to improve it even more. Your feedback will help us identify concrete areas to improve.
the combobox undergone some improvements as we migrated from
popper.js
toangular CDK
.There are multiple ways to engage with the teams. One of then is through our slack . You can also open issue or start a discussion on our repo.
I took the initiative to open an issue from you. Feel free to update or provide more information.
cheers,
Mladen