This article is a deep dive into how an ADF application is configured, built, and run. Specifically for ADF version 1.9.0. It's very much a one-time-only type of read that you would do in the beginning of your first ADF project. It will mostly likely benefit you a lot in the long run to know what's in this article. When you are on top of the stuff in this article you would most likely use generators, or clone a GitHub project, when starting a new ADF project.
There is newer version of this article covering ADF 2.0: https://community.alfresco.com/community/application-development-framework/blog/2017/12/15/generatin...
In this section we will look at what ADF really is.
The Alfresco Application Development Framework, referred to as ADF, is built on top of the Angular 4 JavaScript framework. You can think of ADF as a library of Alfresco web components that can be used to build a content management web application and/or a process management web application.
There are a number of web components that you can use to integrate your web application with Alfresco Content Services (ACS):
And for integrating with Alfresco Process Services (APS) you have the following components:
There are also a number of generic components that are used with both ACS and APS:
These ADF components don’t talk directly to the ACS and APS backend services. There are some layers between them that are worth knowing about before you start hacking. The ADF components talk to ADF services, which in turn talks to the Alfresco JS API, which internally calls ACS and APS via their respective ReST APIs. You could use the both the ADF services and the Alfresco JS API directly from your application if there is no ADF component available to do what you want. In fact, you will quite frequently have to use the ADF services in your application to fetch content nodes, process instances, task instances etc.
The following picture illustrates the architecture of an ADF solution:
The ADF components and services are implemented in Angular, which in turn is implemented in TypeScript. The Alfresco JavaScript library is pure JavaScript and could be used with any other JavaScript framework.
Before we move on it is worth mentioning that there is an ADF application generator that can be very useful if you just want to quickly get going with an ADF project, such as for a demo or proof-of-concept scenario. It covers use cases for both ACS and APS. It can be used to generate the following types of ADF applications:
On the other hand, if you want to know how to create an Angular CLI application from scratch, and how to set it up to work with ADF version 1.9.0. And you want to be able to pick and choose what ADF components to use, building your custom content and/or process management interface, then read on.
Make sure you use the latest 2.0.0* version of the ADF App Generator as older ones will generate an application that maybe has more features than you would like when starting out. When using the generator it should look something like this:
martins-macbook-pro:ADF mbergljung$ yo
? 'Allo Martin! What would you like to do? Ng2 Alfresco App
Make sure you are in the directory you want to scaffold into.
This generator can also be run with: yo ng2-alfresco-app
,****.
,.**. `***** <-_
******** ***** ####
$********::**** ####;
_.-._`***::*** ######
,*******, *::* .;##### @
**********,' -=#####',@@@
***' .,---, ,.-==@@@@@@@@
* /@@@@@',@ @\ '@@@@@@@
'@@@@/ @@@ @@@\ ':#'
!@@@@ @@@@ @@@@@@@@@^
@@@@ @@@@@ @@@@@@@'
`"$ '@@@@@. '##'
'@@@@;'
ADF Angular app generator for Alfresco
Version 2.0.0-beta1
? Your project name ADF
? Application blueprint (Use arrow keys)
❯ Process Service and Content Service
Content Service
Process Service
If you don't see this, then you are running an older version of the generator. Try and install the beta version as follows:
martins-macbook-pro:ADF mbergljung$ npm install generator-ng2-alfresco-app@beta -g
Prerequisites
This article is written with the assumption that you are starting out from scratch with your ADF project and that you are new to ADF development. If you have worked with Angular before that would be good, but it is not absolutely necessary.
The associated source code for this article can be found in this GitHub project. It is highly recommended that you have it available when walking through this tutorial. If for some reason you cannot get the code from this article working, then you can always go to the GitHub project for the source of truth.
In this section we will discuss how to install both ACS and APS so that we have them ready when working with any of the ADF components. You will need Alfresco Content Services version 5.2 or higher, Enterprise or Community edition. For APS you will need an Enterprise version 1.6 or higher (Activiti community edition is not yet supported). The reason you need these new versions is because the Alfresco JavaScript API wraps ReST APIs that require these versions.
If you intend to build a client that will only talk to an ACS server, then don’t install APS, and vice versa.
If you are on a Mac then download Community installer from Download Alfresco Community ECM Now | Alfresco
If your ADF application is only going to talk to ACS, then you don’t have to complete this part, just use the ACS credentials as per installation (e.g. admin/admin).
For the ADF Login component to work properly with both services they need to have the same username and password available. It is also important to make sure that the user has proper permissions within the ACS repository, so files and folders can be managed from ADF applications. The same thing is true for the APS user, which needs to have access to the process applications that should be accessed from the ADF application.
It is common to use admin/admin as username/password for ACS. In APS we will have admin@app.activiti.com/admin set up by default. In APS the email address for a user is also used as the username. It is not possible to create a username such as admin in APS.
So let’s use admin@app.activiti.com/admin as username/password in both services, which means we need to set up a new user in ACS:
Alfresco Application Development Framework (ADF) uses the Node.js JavaScript runtime and the npm package manager. So we need to make sure we have them installed with the correct versions. ADF version 1.9.0 requires Node.js version 8. When setting up an Angular project for ADF development it is recommended to use Angular CLI, so we will install that toolkit as well.
Martins-MacBook-Pro:~ martin$ node -v
v8.6.0
Martins-MacBook-Pro:~ martin$ npm -v
5.4.2
Angular CLI is a Command Line Interface (CLI) to automate your development workflow when working with Angular applications. It allows you to:
To install Angular CLI, run:
Martins-MacBook-Pro:~ martin$ npm install -g @angular/cli
Which will install the ng command globally on your system.
On Mac/Linux you might have to run as root with sudo npm install...
On Windows you might have to open a Command prompt and run as Administrator.
Be prepared that installing Angular CLI might take some time...
To verify whether your installation completed successfully, you can run ng version:
Martins-MacBook-Pro:~ martin$ ng version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
@angular/cli: 1.3.2
node: 8.6.0
os: darwin x64
Now that you have Angular CLI installed, let’s use it to create a new application that we can prepare for ADF development.
To create a new app you use the ng new <app-name> command. It will create a new directory with the app-name and generate all the needed files in it.
The app should support routing between different components (call them pages if you like), so we will add the --routing option. This creates a separate file src/app/app-routing.module.ts. The file includes an empty Routes object that you can fill with routes to different components (i.e. pages). Routing capabilities will come in handy when you start developing a more realistic application that contains multiple pages.
While executing the command stand in the directory where you want to create a subdirectory with the new application:
Martins-MacBook-Pro:ADF mbergljung$ ng new adf-workbench --routing
create adf-workbench/README.md (1103 bytes)
create adf-workbench/.angular-cli.json (1131 bytes)
create adf-workbench/.editorconfig (245 bytes)
create adf-workbench/.gitignore (516 bytes)
create adf-workbench/src/assets/.gitkeep (0 bytes)
create adf-workbench/src/environments/environment.prod.ts (51 bytes)
create adf-workbench/src/environments/environment.ts (387 bytes)
create adf-workbench/src/favicon.ico (5430 bytes)
create adf-workbench/src/index.html (299 bytes)
create adf-workbench/src/main.ts (370 bytes)
create adf-workbench/src/polyfills.ts (2480 bytes)
create adf-workbench/src/styles.css (80 bytes)
create adf-workbench/src/test.ts (1085 bytes)
create adf-workbench/src/tsconfig.app.json (211 bytes)
create adf-workbench/src/tsconfig.spec.json (304 bytes)
create adf-workbench/src/typings.d.ts (104 bytes)
create adf-workbench/e2e/app.e2e-spec.ts (295 bytes)
create adf-workbench/e2e/app.po.ts (208 bytes)
create adf-workbench/e2e/tsconfig.e2e.json (235 bytes)
create adf-workbench/karma.conf.js (923 bytes)
create adf-workbench/package.json (1318 bytes)
create adf-workbench/protractor.conf.js (722 bytes)
create adf-workbench/tsconfig.json (363 bytes)
create adf-workbench/tslint.json (3040 bytes)
create adf-workbench/src/app/app-routing.module.ts (245 bytes)
create adf-workbench/src/app/app.module.ts (393 bytes)
create adf-workbench/src/app/app.component.css (0 bytes)
create adf-workbench/src/app/app.component.html (1107 bytes)
create adf-workbench/src/app/app.component.spec.ts (1103 bytes)
create adf-workbench/src/app/app.component.ts (207 bytes)
Installing packages for tooling via npm.
Installed packages for tooling via npm.
Successfully initialized git.
Project 'adf-workbench' successfully created.
Be prepared that the 'Installing packages for tooling via npm' might take some time..., don't Ctrl-C out of it.
You can already see what files that have been created for the adf-workbench app. You can also list the directory to see what’s there:
Martins-MacBook-Pro:ADF mbergljung$ cd adf-workbench/
Martins-MacBook-Pro:adf-workbench mbergljung$ ls -l
total 656
-rw-r--r-- 1 mbergljung staff 1103 11 Oct 14:32 README.md
drwxr-xr-x 5 mbergljung staff 170 11 Oct 14:32 e2e
-rw-r--r-- 1 mbergljung staff 923 11 Oct 14:32 karma.conf.js
drwxr-xr-x 758 mbergljung staff 25772 11 Oct 14:32 node_modules
-rw-r--r-- 1 mbergljung staff 310433 11 Oct 14:32 package-lock.json
-rw-r--r-- 1 mbergljung staff 1318 11 Oct 14:32 package.json
-rw-r--r-- 1 mbergljung staff 722 11 Oct 14:32 protractor.conf.js
drwxr-xr-x 14 mbergljung staff 476 11 Oct 14:32 src
-rw-r--r-- 1 mbergljung staff 363 11 Oct 14:32 tsconfig.json
-rw-r--r-- 1 mbergljung staff 3040 11 Oct 14:32 tslint.json
Behind the scenes, the following happens:
Let's quickly run through and explain what most of these directories and files mean:
It is preferred to work with the Angular application from a JavaScript IDE such as Visual Studio Code (Open Source) or WebStorm (Paid):
The basic app module and app component have been generated, so you should now be able to run the app from the adf-workbench directory with the ng serve command:
Martins-MacBook-Pro:adf-workbench mbergljung$ ng serve
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
Date: 2017-10-11T13:39:42.302Z
Hash: 7dc0622284b0b56b69da
Time: 6149ms
chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered]
chunk {main} main.bundle.js, main.bundle.js.map (main) 10.5 kB {vendor} [initial] [rendered]
chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 217 kB {inline} [initial] [rendered]
chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 11.3 kB {inline} [initial] [rendered]
chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.61 MB [initial] [rendered]
webpack: Compiled successfully.
Access the app from a browser via http://localhost:4200:
Not much to brag about, but it is a starting point!
Behind the scenes, the following happens:
Notice that the ng serve command does not exit and return to your terminal prompt after step 3. Instead, because it includes LiveReload support, the process actively watches your src directory for file changes. When a file change is detected, step 2 is repeated and a notification is sent to your browser so it can refresh automatically.
This also means that if you make any changes to stuff outside the src/ directory, such as .angular-cli.json, then you need to restart the server for them to take effect.
To stop the process and return to your prompt, press ctrl-c.
Angular CLI is tightly integrated with Webpack, so you will for example not see a webpack.config.js file in the same directory as package.json. Instead all config for things like webapp assets are done in Angular CLI’s config file, .angular-cli.json.
You might be wondering what Webpack is. It's an open-source module bundler for JavaScript applications. When Webpack processes your application, it recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles to be loaded by the browser.
Webpack is a very powerful module bundler. A bundle is a JavaScript file that incorporates assets that belong together and should be served to the client in a response to a single file request. A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.
Webpack scans your application source code, looking for import statements (e.g. import { Component } from '@angular/core';), building a dependency graph, and emitting one or more bundles. With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.
You determine what Webpack does and how it does it with a JavaScript configuration file, webpack.config.js. Angular CLI uses Webpack under the hood, but all configuration for it is instead in .angular-cli.json. You will not see a webpack.config.js in an Angular CLI app.
You can see the bundles that are generated by Webpack for our app when we started it above:
The Angular CLI configuration is done in the .angular-cli.json file and it is important to understand the different parts of this file before moving on. We have already mentioned this file a couple of times and we know that the Webpack configuration is done via this file too, there is no webpack.config.json.
The following list explains the most important parts of the file:
As we can see, everything is controlled via this file.
Every ADF based application will of course need a lot of libraries and resources to run. To add these we update the following files in the adf-workbench application:
It is very important that the libraries we set up as dependencies for the application matches the library versions that the ADF Components expects to use. We will be using ADF version 1.9.0 so we need to find out what Angular version it expects to use, what Google Material Design version it expects, etc. We can do this by using a utility called npm-remote-ls.
Install it like this:
Martins-MacBook-Pro:adf-workbench martin$ npm install -g npm-remote-ls
This installs this utility globally on your machine (-g), and not in the node_modules for the adf-workbench app. To find out the dependencies that ADF version 1.9.0 uses you can pick one of its libraries, such as ng2-alfresco-core, and run the tool on it:
Martins-MacBook-Pro:adf-workbench martin$ npm-remote-ls ng2-alfresco-core@1.9.0
└─ ng2-alfresco-core@1.9.0
├─ @angular/cdk@2.0.0-beta.10
├─ @angular/material@2.0.0-beta.10
├─ @angular/animations@4.3.6
├─ @angular/core@4.3.6
├─ @angular/http@4.3.6
├─ @angular/compiler@4.3.6
├─ @angular/forms@4.3.6
├─ @angular/common@4.3.6
├─ @angular/compiler-cli@4.3.6
├─ hammerjs@2.0.8
├─ core-js@2.4.1
├─ alfresco-js-api@1.9.0
├─ @angular/platform-browser-dynamic@4.2.5
├─ material-design-lite@1.2.1
├─ reflect-metadata@0.1.10
├─ moment@2.15.1
├─ rxjs@5.1.0
├─ zone.js@0.8.12
├─ @angular/material@2.0.0-beta.10
├─ @angular/platform-browser-dynamic@4.3.6
├─ @ngx-translate/core@7.0.0
├─ core-js@2.4.1
Note that I have not included all listed libraries, just the ones of most importance.
Here we can immediately find out the expected versions for several important libraries:
We now have all the necessary version information to be able to configure the application with the necessary dependencies and resources so ADF version 1.9.0 will work smoothly.
To check dependencies for a beta version do for example:
Martins-MacBook-Pro:workbench-x martin$ npm-remote-ls ng2-alfresco-core@1.9.0-beta7
Start by updating the generated application to correct Angular version 4.3.6. Open package.json and update it to look as follows:
{
"name": "adf-workbench",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"core-js": "^2.4.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
},
"devDependencies": {
"@angular/cli": "1.4.1",
"@angular/compiler-cli": "4.3.6",
"@angular/language-service": "4.3.6",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "~3.1.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.3.2",
"typescript": "~2.3.3"
}
}
Note here that we changed ^4.2.4 to 4.3.6, removing also the caret, which otherwise will update you to the latest version.
The Core.js version is the same. Just need to remove the caret. Open package.json and update the dependencies section to look as follows:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"core-js": "2.4.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
...
The styling of the ADF Components is based on Google Material Design. In this section we add the necessary styles, images, and JavaScript libraries.
Material Design Lite lets you add a Material Design look and feel to your websites. It doesn’t rely on any JavaScript frameworks and aims to optimize for cross-device use, gracefully degrade in older browsers, and offer an experience that is immediately accessible.
Add the material design dependency to the dependencies section in the package.json file:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
},
...
The Google Material Design Icons should be loaded via the src/index.html file, update it as follows:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AdfWorkbench</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Muli" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
</body>
</html>
We also need to make sure these libraries (i.e. styles and JS) are loaded correctly during runtime. The styles and JS files will be packaged up into a bundle by the webpack process. Angular CLI is integrated with webpack behind the scenes.
In the styles and scripts sections in the .angular-cli.json file, add as follows:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "adf-workbench"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css",
"../node_modules/material-design-lite/dist/material.orange-blue.min.css"
],
"scripts": [
"../node_modules/material-design-lite/material.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
...
These styles will be loaded exactly as if you had added them in a <link> tag inside index.html. And the JavaScript file will be loaded exactly as if you added it in a <script> tag inside index.html. You might be tempted to just specify these in the index.html file directly, doing this will not get them packaged up into a bundle by webpack.
The apps[0].styles will end up in the dist/styles.bundle.js bundle file and the apps[0].scripts will end up in the dist/scripts.bundle.js bundle file.
Note that we are referencing the node_modules directory relatively from the src directory, not from the directory where the .angular-cli.json file is located.
As you can see from the above app[0].styles configuration the styles.css file was already included in our .angular-cli.json file. This is where you add style information that is relevant to the entire application. And that is also why we added the Material Design style sheets here. And so far, this is what you would expect. But, as you know, Angular 2 takes styling to the next level.
Assuming you have done a bit of Angular 2 (4) web development, you know that you can also add style information in your components. If you open the existing src/app/app.component.ts file, you will notice that there is both a templateUrl and a styleUrls attribute in the @Component() metadata section:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}
In the styleUrls property you can specify a list of relative URLs of CSS files to include.
If we include CSS information in the CSS files, you will see that when we render the page, the CSS gets rewritten so that the CSS is scoped to the component. Looking at an ADF component, such as the LoginComponent, we can see that this is used:
@Component({
selector: 'adf-login, alfresco-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
host: {'(blur)': 'onBlur($event)'},
encapsulation: ViewEncapsulation.None
})
export class LoginComponent implements OnInit {
As ADF is implemented in Angular 4 we need to also install the Material Design components that are built for and with Angular. We can then also use these Angular Material components when building our UI.
Open up package.json and add the angular/cdk and angular/material library dependencies:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
}...
The Angular CDK is comprised of a bunch of services, directives, components, classes, modules, etc to make our lives easier when developing Angular components. The CDK actually provides general-purpose tools for building components that are not coupled to Material Design.
In this section we add some libraries that are used throughout the ADF components.
The moment library provides Angular pipes for manipulating display of date and time. Add it as a dependency in package.json:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
},
Ngx-Translate is an internationalization library for Angular 2+. It lets you define translations for your content in different languages and switch between them easily. Add it as a dependency in package.json:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"rxjs": "^5.4.2",
"zone.js": "^0.8.14"
}...
The Reactive Extensions for JavaScript (RxJS) is a set of libraries to compose asynchronous and event-based programs using observable collections and Array#extras style composition in JavaScript.
The version of RxJS in the generated project is not correct, update it as follows in package.json:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"rxjs": "5.1.0",
"zone.js": "^0.8.14"
},
Fix type warnings related to the RxJS library
To switch off numerous and unnecessary type warnings related to the RxJs library, update the root Typescript configuration (for the IDE) file adf-workbench/tsconfig.json and the skipLibCheck and paths properties as follows:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
],
"skipLibCheck": true,
"paths": {
"rxjs/*": ["../node_modules/rxjs/*" ],
"@angular/*": ["../node_modules/@angular/*"]
}
}
}
The Zone library provides a way to represent the dynamic extent of asynchronous calls in Node. Just like the scope of a function defines where it may be used, the extent of a call represents the lifetime that is it active.
The version of Zone in the generated project is not correct, update it as follows in package.json:
{
"name": "adf-workbench",
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"rxjs": "5.1.0",
"zone.js": "0.8.12"
}...
By default the generated project will have the typescript version configured in a way such as this:
"typescript": "~2.3.3"
This is not ideal as the tilde character in front of it means that whenever a patch version is released by Microsoft, such as version 2.3.4, our project could be updated with the new version without us realising it. This can be bad news as this could effect some ADF component, and it could take a while before we realise what is going on. So remove the tilde and specify it as follows instead in the dev dependencies section:
"devDependencies": {
"@angular/cli": "1.4.1",
"@angular/compiler-cli": "4.3.6",
"@angular/language-service": "4.3.6",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "~3.1.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.3.2",
"typescript": "2.3.3"
}
There are general libraries used throughout the Application Development Framework (ADF) that are useful to install at the beginning. We can also do basic configuration of the ADF app.
Alfresco ADF components uses the Alfresco JavaScript library to talk to ACS and APS. This JavaScript library basically abstracts the Content Services REST API and the Process Services REST API.
Add it as follows in package.json:
{
"name": "adf-workbench",
...
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"alfresco-js-api": "1.9.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"ng2-alfresco-core": "1.9.0",
"rxjs": "5.1.0",
"zone.js": "0.8.12"
},
This JS library can also be used directly in cases where there are no ADF components that fit the requirements. Note that the Alfresco JavaScript library follows the same versioning as the ADF, so we specify 1.9.0.
The ADF Core components and services provide stuff such as Menu component, Toolbar component, Authentication Service, Alfresco Content Services, Notification Service, Search Service etc, which are used throughout the ADF.
Add this library in package.json:
{
"name": "adf-workbench",
...
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"alfresco-js-api": "1.9.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"ng2-alfresco-core": "1.9.0",
"rxjs": "5.1.0",
"zone.js": "0.8.12"
},
We also need to tell the app about the assets and styles that are available in the ADF core library. We want these assets and styles to be packaged and bundled up by the webpack tool, making them available during runtime.
Add the new asset to the assets sections, new styles to the styles section, and the new stylePreprocessorOptions property in the .angular-cli.json file:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "adf-workbench"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico",
{ "glob": "**/*", "input": "../node_modules/ng2-alfresco-core/bundles/assets", "output": "./assets/" }
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css",
"../node_modules/material-design-lite/dist/material.orange-blue.min.css",
"../node_modules/ng2-alfresco-core/prebuilt-themes/adf-blue-orange.css"
],
"scripts": [
"../node_modules/material-design-lite/material.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
},
"stylePreprocessorOptions": {
"includePaths": [
"../node_modules/ng2-alfresco-core/styles"
]
}...
What we do here in the app[0].assets section is to tell Angular CLI that all the assets, such as images and i18n resource files, that are located in the ng2-alfresco-core package should be copied into the dist/assets directory.
We also configure what ADF theme (Angular Material theme) we want to use, in this case adf-blue-orange.css. The theme will be available to the whole app we are building.
In order to simplify style imports we also add style include paths as follows via the stylePreprocessorOptions entry in .angular-cli.json:
"stylePreprocessorOptions": {
"includePaths": [
"../node_modules/ng2-alfresco-core/styles"
]
}
Files in that folder, for example, src/../node_modules/ng2-alfresco-core/styles/_colors.scss, can be imported from anywhere in your project without the need for a relative path:
/* src/app/app.component.scss
A relative path works */
@import '../node_modules/ng2-alfresco-core/styles/colors';
/* But now this works as well */
@import 'colors';
Install all libraries
It’s time to install all the libraries that we defined in package.json. We need to do this now otherwise it will be difficult to work with the components from our IDE as it would not know anything about the modules and classes we are trying to use. Basically we need to get the local /node_modules directory updated with all the new libraries that we configured and the updated library versions.
Remove the node_modules directory and then run npm install to download all the extra libraries that we have defined in package.json to node_modules:
Martins-MacBook-Pro:adf-workbench mbergljung$ rm -rf node_modules/
Martins-MacBook-Pro:adf-workbench mbergljung$ npm install
...
Testing binary
Binary is fine
added 1030 packages in 13.195s
Martins-MacBook-Pro:adf-workbench mbergljung$ npm dedup
removed 16 packages in 2.949s
After we have run npm install we also run npm dedup. This will remove any duplicate transitive dependencies. If a transitive dependency already exists it will not be downloaded again, but this depends on the order we have specified the libraries in package.json. So always good to do a dedup after an install.
You might be tempted to run npm update instead of npm install. This will also work but it changes package.json dependencies version specifications. It will add carets in front of version numbers, so not what we want. So be careful with this command.
List the node_modules directory if you want to find out all the downloaded libs:
Martins-MacBook-Pro:node_modules mbergljung$ ls -l|more
total 0
drwxr-xr-x 14 mbergljung staff 476 11 Oct 15:30 @angular
drwxr-xr-x 5 mbergljung staff 170 11 Oct 14:32 @angular-devkit
drwxr-xr-x 4 mbergljung staff 136 11 Oct 14:32 @ngtools
drwxr-xr-x 3 mbergljung staff 102 11 Oct 15:30 @ngx-translate
drwxr-xr-x 3 mbergljung staff 102 11 Oct 14:32 @schematics
drwxr-xr-x 7 mbergljung staff 238 11 Oct 14:32 @types
drwxr-xr-x 6 mbergljung staff 204 11 Oct 14:32 abbrev
drwxr-xr-x 7 mbergljung staff 238 11 Oct 14:32 accepts
drwxr-xr-x 9 mbergljung staff 306 11 Oct 14:32 acorn
drwxr-xr-x 9 mbergljung staff 306 11 Oct 14:32 acorn-dynamic-import
drwxr-xr-x 10 mbergljung staff 340 11 Oct 14:32 adm-zip
drwxr-xr-x 9 mbergljung staff 306 11 Oct 14:32 after
...
Note here that the ng2-alfresco-core library has all its dependencies specified in its own package.json, as would be expected, and we call these transitive dependencies. As we saw earlier on, we can easily find out the dependencies for a library we use with the npm-remote-ls tool.
Now it's time to make sure that the package.json for our adf-workbench application has been configured with matching ADF 1.9 libraries. In your IDE, navigate into the node_modules directory and look up the ng2-alfresco-core library. You should see something like this:
We should not see any node_modules directory for the ng2-alfresco-core library if we have configured the app’s package.json correctly. On the other hand, if we have not configured the same library versions as ADF 1.9 expects, then we would see something like this:
And this means that we will most likely experience problems during runtime, if we can get it to work at all.
Make sure that the app you are building uses the same versions for all libraries that ADF depends on.
The ADF Core module provides all the services that the ADF components needs, such as
AuthenticationService, AlfrescoContentService, TranslationService etc. It also provides some components, such as Toolbar, Card View, and Accordion, which might be used frequently.
Open up the src/app/app.module.ts file and import the ADF CoreModule from the ng2-alfresco-core package:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from 'ng2-alfresco-core';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
CoreModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
If you open up the CoreModule file you can see that it defines the following providers:
@NgModule({
imports: [
...
declarations: [
...
],
providers: [
...providers(),
...deprecatedProviders(),
MomentDateAdapter,
{
provide: TRANSLATION_PROVIDER,
multi: true,
useValue: {
name: 'ng2-alfresco-core',
source: 'assets/ng2-alfresco-core'
}
}
],
exports: [
...
],
entryComponents: [
...
]
})
export class CoreModule {
If we navigate into the providers() method we can see all services that are exported and available:
export function providers() {
return [
UserPreferencesService,
NotificationService,
LogService,
LogServiceMock,
AuthenticationService,
AlfrescoContentService,
AlfrescoSettingsService,
StorageService,
CookieService,
AlfrescoApiService,
AlfrescoTranslateLoader,
TranslationService,
RenditionsService,
ContentService,
AuthGuard,
AuthGuardEcm,
AuthGuardBpm,
ThumbnailService,
UploadService,
SearchService,
DeletedNodesApiService,
FavoritesApiService,
NodesApiService,
PeopleApiService,
SearchApiService,
SharedLinksApiService,
SitesApiService,
DiscoveryApiService,
HighlightTransformService
];
}
The ADF app needs to be configured with the location of the ACS and the APS servers. We don’t want to hardcode this in component code. Fortunately there is a file called app.config.json that can be used for this. The ADF framework will automatically look for it.
Create it with the following content and put it in the src/assets directory:
{
"ecmHost": "http://{hostname}:{port}/ecm",
"bpmHost": "http://{hostname}:{port}/bpm",
"application": {
"name": "ADF Workbench"
}
}
You are probably wondering about the URLs. What values would be substituted for the hostname and port variables, and what about the /ecm and /bpm URL paths, they don’t match endpoints in the ACS and APS servers that we installed earlier on.
First, at runtime the {hostname} and {port} variables will be replaced with the data from the running application, such as localhost and 4200. Secondly, the /ecm and /bpm paths are used to talk to a proxy configured in Webpack. We need to add a file called adf-workbench/proxy.conf.json with the following content:
{
"/ecm": {
"target": "http://127.0.0.1:8080",
"secure": false,
"pathRewrite": {
"^/ecm": ""
}
},
"/bpm": {
"target": "http://127.0.0.1:9080",
"secure": false,
"pathRewrite": {
"^/bpm": ""
}
}
}
The target URLs need to match the installations we did earlier on for ACS and APS. The pathRewrites shows the answer to the second question about the /ecm and /bpm URLs not matching endpoints in ACS or APS. Here they are removed by the proxy.
If you are using just one of the backend services, for example ACS. Then you don't need to worry about configuring the other one (e.g. /bpm). And vice versa.
Now, the proxy.conf.json file is not magically read by Webpack, we need to configure Webpack with the location of it. Open up package.json and update the start script as follows:
{
"name": "adf-workbench",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
…
By using the Webpack proxy we don’t need to configure CORS in ACS or APS.
So what all this means is that a call to for example ACS will be using the http://localhost:4200/ecm URL, which does not cause any CORS problems as the host and port are the same as where the app is running. This URL will then be rewritten via the Webpack proxy to http://127.0.0.1:8080/, where the ACS backend is running.
The first thing that we are going to need to do in our app is to login to Content Services and/or Process Services. We can do this with the ADF Login component. When we have a session with these services we can start using other components, such as the Document List.
The login component is available in the ng2-alfresco-login library. Install version 1.9.0 of it like this:
martins-macBook-pro:adf-workbench martin$ npm install --save --save-exact ng2-alfresco-login@1.9.0
+ ng2-alfresco-login@1.9.0
added 2 packages in 5.1s
Note that we should not see any other transitive dependencies being downloaded. They should all match what we already have.
When we run the install command with the --save switch it will automatically add the ng2-alfresco-login package to our package.json. Adding the --save-exact option writes the exact version, such as 1.9.0, instead of with a caret ^1.9.0. If the library version is added with a caret (^) in front of it, and there were to be a newer version of ADF released such as 1.9.1, then that version would be used instead.
In the package.json we should see something like this:
{
"name": "adf-workbench",
"version": "0.0.0",
"license": "MIT",
"scripts": {
...
},
"private": true,
"dependencies": {
"@angular/animations": "4.3.6",
"@angular/cdk": "2.0.0-beta.10",
"@angular/common": "4.3.6",
"@angular/compiler": "4.3.6",
"@angular/core": "4.3.6",
"@angular/forms": "4.3.6",
"@angular/http": "4.3.6",
"@angular/material": "2.0.0-beta.10",
"@angular/platform-browser": "4.3.6",
"@angular/platform-browser-dynamic": "4.3.6",
"@angular/router": "4.3.6",
"@ngx-translate/core": "7.0.0",
"alfresco-js-api": "1.9.0",
"core-js": "2.5.1",
"material-design-lite": "1.2.1",
"moment": "2.15.1",
"ng2-alfresco-core": "1.9.0",
"ng2-alfresco-login": "1.9.0",
"rxjs": "5.1.0",
"zone.js": "0.8.12"
},
"devDependencies": {
...
}
}
We also need to tell the app about the assets, such as i18n resources, that are available in the ADF Login library. We want these assets to be packaged and bundled up by the webpack tool, making them available during runtime.
Add the login assets to the .angular-cli.json file as follows:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "adf-workbench"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico",
{ "glob": "**/*", "input": "../node_modules/ng2-alfresco-core/bundles/assets", "output": "./assets/" },
{ "glob": "**/*", "input": "../node_modules/ng2-alfresco-login/bundles/assets", "output": "./assets/" }
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css",
"../node_modules/material-design-lite/dist/material.orange-blue.min.css",
"../node_modules/ng2-alfresco-core/prebuilt-themes/adf-blue-orange.css"
],
"scripts": [
"../node_modules/material-design-lite/material.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
},
"stylePreprocessorOptions": {
"includePaths": [
"../node_modules/ng2-alfresco-core/styles"
]
}
}
],
...
}
Every ADF component has extensive documentation available together with the source code in the standard README.md. For example, if you navigate to the Login component source code you would see something like this:
The page covers everything from documentation, installation, basic usage, to advanced concepts. Click on the Documentation link in the bullet point list to read more about the Login component. The basic markup that will put the login component onto the page looks like this:
<adf-login
[providers]="'ALL'"
(onSuccess)="mySuccessMethod($event)"
(onError)="myErrorMethod($event)">
</adf-login>
The providers property controls what backing services to connect to. By default it will connect only to the Content Services (i.e. providers value set to 'ECM'). By specifying ALL we make sure to login to both Content Services and Process Services.
If you are using only one of the backend services, such as APS, then make sure to specify only that service in the providers field (e.g. ‘ECM’ if logging in only to ACS and 'BPM' if logging in only to APS).
The two event callback methods will be invoked when a successful login has completed (onSuccess) or if an error occurs (onError).
The application that we generated comes with only one component, the main application component, represented by the TypeScript class AppComponent defined in the src/app/app.component.ts file. The view template is available in the src/app/app.component.html file.
To use the login component from the app component we need to first import it. The Alfresco Login Component is defined in the TypeScript class LoginComponent. The import is done implicitly via a module called LoginModule, which should be added to the AppModule in the src/app/app.module.ts file as follows:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from 'ng2-alfresco-core';
import { LoginModule } from 'ng2-alfresco-login';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
CoreModule,
LoginModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
If you look in the LoginModule file you can see that it exports the LoginComponent and some directives at the root level. Any component that exist, or we create, can now use the login component.
To quickly test the Login component we will add it to the existing root app component. Open up the src/app/app.component.html template file, you should see some markup like this:
<!--The content below is only a placeholder and can be replaced.-->
<divstyle="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
<img width="300" src="data:image/svg+xml;base64,PD94...">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<<>li
h2><a target="_blank" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" href="https://blog.angular.io//">Angular blog</a></h2>
</li>
</ul>
<router-outlet></router-outlet>
Change the template to look like this instead, with the Login component added:
<div style="text-align:center">
<h1>
Welcome to {{title}}!
</h1>
</div>
<adf-login
[providers]="'ALL'"
(onSuccess)="onLoginSuccess($event)"
(onError)="onLoginError($event)">
</adf-login>
<router-outlet></router-outlet>
Keep the router-outlet as that is where the router will output other components template code. It does not do anything at the moment as we don’t have any other components with routes, but we will keep it anyway.
Note. change [providers]="'ALL'" if you are just using one of the backing services.
The Alfresco Login component emits two events called onSuccess and onError, indicating the outcome of the login attempt. We will define new handler methods in the App component class as follows (src/app/app.component.ts😞
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'ADF Workbench';
onLoginSuccess($event) {
console.log('Successful login: ' + $event.value);
}
onLoginError($event) {
console.log('Failed login: ' + $event.value);
}
}
Note. also updated the title property to “ADF Workbench”.
It’s time to run the app and see how it looks. We would expect to see a login page.
Start the server by running npm start:
Martins-MacBook-Pro:workbench-x martin$ npm start
> workbench-x@0.0.0 start /Users/martin/ADFProjects/workbench-x
> ng serve --proxy-config proxy.conf.json
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200 **
Date: 2017-09-06T10:17:58.335Z
Hash: 6216512973110e2481bf
Time: 20194ms
chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 5.83 kB [entry] [rendered]
chunk {main} main.bundle.js, main.bundle.js.map (main) 18.3 kB {vendor} [initial] [rendered]
chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 174 kB {inline} [initial] [rendered]
chunk {scripts} scripts.bundle.js, scripts.bundle.js.map (scripts) 64.5 kB {inline} [initial] [rendered]
chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 254 kB {inline} [initial] [rendered]
chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 7.91 MB [initial] [rendered]
webpack: Compiled successfully.
You should see all Webpack bundles created and the app launched successfully. Note that we use npm start instead of ng serve as we want the Webpack proxy to be active.
Accessing the app on http://localhost:4200 should show the login page as follows:
Pretty cool!
Let’s try and login with the common username and password:
Clicking SIGN IN should log you in successfully to ACS and/or APS. The login screen will change to the following with a “Login successful” message and the button change message to WELCOME:
The JavaScript console in the browser should show you log from the callback method onLoginSuccess:
Everything is working fine now and we are logged in to ACS and/or APS.
To use Angular CLI to set up an Angular application is really easy. And to configure it to work with ADF 1.9.0 is not that difficult either. It was all done to get you up to speed on how everything hangs together. Of course it is also possible to generate an ADF application with the Yeoman generator when you are on top of how things work together. Or just clone an ADF ready Angular CLI project.
We can now start bringing in some more ADF components. However, before we do that it might be a good idea to refactor/restructure the app a bit so it resembles a more realistic application with toolbar, menu, logout etc, read the
Adding Navigation, Menu, Toolbar, and Logout to your ADF 1.9 App article for more info on how to do that.