After a detailed overview of the available services and components of the Alfresco Application Development Framework, in this tutorial we are going to see how to create new pages into an existing application. To complete the tutorial, we are going to show how to create custom Angular 2 components to define a specific behaviour for a specific user experience.
We would like here to remember that Alfresco Application Development Framework (from now on ADF) is provided by Alfresco as Open Source, to build custom applications on top of the Activiti BPM Engine and Alfresco ECM Repository.
We won’t introduce here the basis of the Alfresco ADF, because we would like to focus the content on customising an existing ADF application. To better describe the tasks, we are going to use “a step by step“ approach, more practical and easy to follow for our goal. If you would prefer to discover other details about ADF, please go through the getting started page (coming soon).
For further details about the Alfresco ADF, please refer to the alfresco-ng2-components GitHub Project and take a look to the Alfresco Catalog, with a friendly (and technical) overview of all the available components. For requests of support, questions and feedback, don’t forget to participate to the Community of Developers dedicated to the ADF or to the Gitter space dedicated to the Alfresco Angular 2 components.
Starting from the my-adf
application, created with the Yeoman Generator exactly in the same way it is described in the ADF 101 tutorial, what we are going to do is adding a new page to the existing application. After this task, we will link the new page to the various menu, with a focus on the technical details for a better comprehension.
Assuming the my-adf
application is up and running, let’s face the task in different actions, one for each source code change. More in detail we are going to:
MyFirstPageComponent
, useful to manage the view.MyFirstPageComponent
into the app root module, managing the list of Angular 2 components and the Angular 2 routing to enable the navigation from one view to the next.my-adf
application.Below a paragraph detailing each development with further details.
MyFirstPageComponent
to manage the viewAs we saw in the previous tutorials, a generic patch of screen of an ADF application, is called view and is managed from a standard Angular 2 component. Because of this reason, the first task of this example is about developing the MyFirstPageComponent
. The goal of the component is to show the simplest Hello World message into the screen. As described several times in the past tutorials, the development of an Angular 2 component is very straightforward and can be done as described below.
Starting from the <my-adf>/app/components
path, let’s create a new folder named myfirstpage
. Inside the new folder, let’s create three files: myfirstpage.component.css
, myfirstpage.component.html
and myfirstpage.component.ts
. All the three files together, define the Angular 2 component. Below you can find the content you should copy (or digit) into each file.
myfirstpage.component.css
.container {
margin: 10px;
}
@media only screen and (max-width: 640px) {
.container {
margin: 0;
}
}
myfirstpage.component.html
<div class="container">
<h1>Hello world!</h1>
</div>
myfirstpage.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'myfirstpage-component',
templateUrl: './myfirstpage.component.html',
styleUrls: ['./myfirstpage.component.css']
})
export class MyFirstPageComponent {}
After the creation, the myfirstpage
folder should looks like the picture below.
The myfirstpage
folder of the my-adf
application.
Now that the MyFirstPageComponent
is created, it’s time to include it in the index.ts
file containing the links between the alias of each component and the source code. For this purpose, let’s edit the index.ts
file stored into the <my-adf>/app/components
folder and modify it, according to the description below.
// Add this at the end of the ‘index.ts’ file.
export { MyFirstPageComponent } from './myfirstpage/myfirstpage.component';
At this stage, the MyFirstPageComponent
is correctly setup but not visible to the my-adf
application.
MyFirstPageComponent
into the root moduleTo make the MyFirstPageComponent
visible to the my-adf
application, let’s act on the root module. Edit the app.module.ts
file stored into the <my-adf>/app
folder and change the content according to the description below.
import {
...
MyFirstPageComponent, // Add this import.
...
} from './components/index';
@NgModule({
...
declarations: [
...
MyFirstPageComponent, // Add this declaration.
...
],
...
})
export class AppModule {}
Once the MyFirstPageComponent
is visible to the my-adf
application, the next step is to define the Angular 2 routing to enable the navigation from and to the view. To develop the routing, let’s act on the app.routes.ts
file stored into the <my-adf>/app
folder. Below the details of the changes to apply to the content.
import {
...
MyFirstPageComponent, // Add this import.
...
} from './components/index';
export const appRoutes: Routes = [
...
// Add the content below here.
{
path: 'myfirstpage',
component:MyFirstPageComponent
,
canActivate: [AuthGuard]
},
...
];
With the changes above, the MyFirstPageComponent
component is routed with the http://localhost:3000/myfirstpage
URL (assuming you run the my-adf
application on localhost
at port 3000
).
Please remember that after each saving of one or more files, the Angular 2 Webpack will update the my-adf
application, trying to refresh the view with the latest updates. Of course, before completing this task, the my-adf
application is not ready to be used and some errors could appear in the log.
myfirstpage
into the my-adf
applicationNow that all the changes are completed and the myfirstpage
is available as view, let’s see in the picture below how it looks like.
The myfirstpage
view of my-adf
application.
As you can see, the new page is the simplest we can imagine and it is designed to share how to develop the creation of a brand new page and how to add it to an Alfresco ADF application. For more advanced customizations, we are going to share further examples below in the document, but before we would like to see how to add the new page to the two available menus (one on the top bar and the other to the hidden left panel).
To reach the goal, let’s act as usually described in the past examples: identifying the component to be modified and only after developing the changes. As discussed in the past, the upper menu in cyan and the hidden left panel containing the other menu, are both managed into the app component. To develop the changes, let’s edit the app.component.html
file stored into the <my-adf>/app
folder. Below the details of the changes to apply to the content.
...
<!-- Navigation. We hide it in small screens. -->
<nav class="mdl-navigation mdl-layout--large-screen-only">
...
<a class="mdl-navigation__link" data-automation-id="activiti" href="" routerLink="/activiti">Activiti</a>
<!-- Add the content below -->
<a class="mdl-navigation__link" data-automation-id="myfirstpage" href="" routerLink="/myfirstpage">My first page</a>
...
</nav>
...
<span class="mdl-layout-title">Components</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="" routerLink="/" (click)="hideDrawer()">Home</a>
<!-- Add the content below -->
<a class="mdl-navigation__link" href="" routerLink="/myfirstpage" (click)="hideDrawer()">My first page</a>
...
</nav>
Saving the app.component.html
file, you will see that the application will be automatically updated and the new items will be visible into the menus. Of course, clicking on the links, both will show the myfirstpage
view. In the picture below you can see how the home looks like, with highlights on both the menu items.
The home page of my-adf
application with the new menu items highlighted.
For further details on how to create (and manage) a page into an Alfresco ADF application, please consider that what is described here is nothing more and nothing less than a standard Angular 2 solution. For further details on Angular 2 routing, please refer to the official documentation.
Now that we know how to create new pages into an Alfresco ADF application, let’s discuss further details on how to add existing components to a view. Even if we didn’t explain how to do it, in the past tutorials we used this solution several times. More in detail, the idea is to enrich the HTML template of the view component, with custom code and tags related to other out-of-the-box or custom components.
In this example we are going to modify the new myfirstpage
view, adding two out-of-the-box components of the Alfresco ADF: the Activiti task list (ng2-activiti-tasklist
) and the Alfresco document list (ng2-alfresco-documentlist). To start developing, let’s edit the myfirstpage.component.html
file stored into the <my-adf>/app/components/myfirstpage
folder. Below you can find the content you should copy (or digit), replacing the existing one.
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--12-col task-column mdl-shadow--2dp">
<activiti-tasklist
[appId]="'1'"
[state]="'open'"
[assignment]="'assignee'">
</activiti-tasklist>
</div>
<div class="mdl-cell mdl-cell--12-col task-column mdl-shadow--2dp">
<alfresco-document-list
#documentList
[currentFolderId]="'-root-'"
[contextMenuActions]="true"
[contentActions]="true"
[creationMenuActions]="false">
</alfresco-document-list>
</div>
</div>
For further details about the activiti-tasklist
and the alfresco-document-list
components, please refer to the official documentation. Saving the myfirstpage.component.html
file, you will see that the application will be updated automatically. Below a picture showing how the myfirstpage
page looks like into our development environment, after restarting.
The myfirstpage
view with two out-of-the-box ADF components.
For further details about the out-of-the-box ADF components, please refer to the alfresco-ng2-components GitHub Project and take a look to the Alfresco Catalog, with a friendly (and technical) overview of all the available components.
After the inclusion of the two components into the myfirstpage
page, let’s see how to interact with other pages and navigating between all the available views. As an example, let’s see how to navigate to the task details, clicking on a row of the task list, and how to navigate into the repository, clicking into a row in the document list.
Before changing the source code, let’s study a little bit more the available views. To have a full list of the available views, let’s edit the app.routes.ts
file into the <my-adf>/app
folder. As a reminder, app.routes.ts
defines the Angular 2 routing as a list of paths in relation to the components. As you can see below, two views in particular could help us in our example.
...
{
path: 'files/:id',
component: FilesComponent,
canActivate: [AuthGuardEcm]
},
...
{
path: 'activiti/tasks/:id',
component: FormViewer,
canActivate: [AuthGuardBpm]
},
...
The first view (available at the path files/:id
) rendering the repository, starting from the id
parameter containing the Alfresco UUID. The second view (available at the path activiti/tasks/:id
) rendering the task details, starting from the id
parameter containing the Activiti task identifier (a number).
Now that we know the target paths, let’s change the myfirstpage.component.html
file stored into the <my-adf>/app/components/myfirstpage
folder as described below.
...
<activiti-tasklist
...
(rowClick)="taskClicked($event)"> <!-- Add this. -->
</activiti-tasklist>
...
<alfresco-document-list
...
(nodeClick)="nodeClicked($event)"> <!-- Add this. -->
</alfresco-document-list>
...
With those changes, the Alfresco ADF components are instructed to execute the taskClicked
method if a row in the activiti-tasklist
component is clicked, and the nodeClicked
method, in case of click on a row of the alfresco-document-list
component. In both cases, useful information are passed in the event variable as a parameter of the methods.
Now that the HTML template is ready, let’s edit the myfirstpage.component.ts
file stored into the <my-adf>/app/components/myfirstpage
folder as described below.
// Add this import.
import { Router } from '@angular/router';
@Component({
...
})
export class MyFirstPageComponent {
// Add this method.
constructor(public router: Router) {
}
// Add this method.
taskClicked(event: string) {
this.router.navigate(['activiti/tasks/' + event]);
}
// Add this method.
nodeClicked(event: any) {
this.router.navigate(['files/' + event.value.entry.id]);
}
...
With those changes, the view component declares the Angular 2 router object into the router attribute and uses the router to change the view according to the click on the row of the two components. In both cases the event variable is used to define what is useful to the target view (in both cases the identifier of the target entity: task or repository node).
Saving myfirstpage.component.html
and myfirstpage.component.ts
, you will see that the application will be updated automatically. Below a picture showing how the target view looks like, after clicking on a task of the task list.
The target view after clicking on the task list of the myfirstpage
view.
To complete the navigation sample, below you see a picture showing how the target view looks like, after clicking on the User Homes
folder of the repository.
The target view after clicking on the User Homes
folder of the repository in the myfirstpage
view.
For further details on how to manage the navigation into an Alfresco ADF application, please consider that what is described here is nothing more and nothing less than a standard Angular 2 solution. For further details on Angular 2 routing, please refer to the official documentation.
Now that we know how to create pages into an Alfresco ADF application and we know how to navigate into and from them, let’s refactor the source code to separate the component representing the page from the content with the two out-of-the-box components: activiti-tasklist
and alfresco-document-list
. The goal is to define a “wrapper” in a new component, with some settings. More in particular we want to develop a new component called myfirstadf
, showing the task list and the document list, in the same view, with the option to see only one of the two. After completing this exercise, we will have something similar to a new “ADF component”, available for your custom application.
To develop this new example we need to refactor the source code introduced above, with some changes to make the new component more similar to a bundled ADF component. Below a description of each change, file per file, for a better comprehension. Considering that the changes have an impact on many files, we suggest to stop the my-adf
application (if running), apply the changes and then restart it again.
In this task we are going to clean the source code that will be moved into a new component called myfirstadf
. The new myfirstadf
component will be developed with a couple of settings (viewTasks
and viewContent
), to control which Alfresco ADF component should be shown. Below the changes to the myadfpage
component.
myfirstpage.component.css
// Clean all the code and leave the file empty.
myfirstpage.component.html
<!-- Clean all the code and replace all the content with what you read below. -->
<myfirstadf-component
[viewTasks]="true"
[viewContent]="true">
</myfirstadf-component>
myfirstpage.component.ts
// Clean all the code and replace all the content with what you read below.
import { Component } from '@angular/core';
@Component({
selector: 'myfirstpage-component',
templateUrl: './myfirstpage.component.html',
styleUrls: ['./myfirstpage.component.css']
})
export class MyFirstPageComponent {}
Before leaving this part, please note how the myfirstadf-component
is invoked into the myfirstpage.component.html
file with the viewTasks
and viewContent
attributes set to true
. In the next section we are going to create the myfirstadf
component to wrap the two Alfresco ADF components: activiti-tasklist
and alfresco-document-list
. The new myfirstadf
component will be shown where the myfirstadf-component
tag is placed into the myfirstpage.component.html
file.
myfirstadf
componentIn the past examples (also in the past tutorials) we did the exercise to create a new component several times. In this example in particular, we are going to refactor the source code to have a unique myfirstadf
component, managing the two out-of-the-box ADF components.
Starting from the <my-adf>/app/components/myfirstpage
folder, let’s create three new files: myfirstadf.component.css
, myfirstadf.component.html
and myfirstadf.component.ts
. All the three files together, define the myfirstadf
Angular 2 component. Below you can find the content you should copy (or digit) into each file.
myfirstadf.component.css
.container {
margin: 10px;
}
@media only screen and (max-width: 640px) {
.container {
margin: 0;
}
}
myfirstadf.component.ts
import { Component, Input } from '@angular/core';
import { Router } from '@angular/router';
import { ObjectDataTableAdapter, DataSorting } from 'ng2-alfresco-datatable';
@Component({
selector: 'myfirstadf-component',
templateUrl: './myfirstadf.component.html',
styleUrls: ['./myfirstadf.component.css']
})
export class MyFirstADFComponent {
@Input() viewTasks: boolean = false;
@Input() viewContent: boolean = false;
dataColumns: ObjectDataTableAdapter;
constructor(public router: Router) {
this.dataColumns = new ObjectDataTableAdapter([], [
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true}
]);
this.dataColumns.setSorting(new DataSorting('name', 'desc'));
}
taskClicked(taskId: string) {
this.router.navigate(['activiti/tasks/' + taskId]);
}
nodeClicked(event: any) {
this.router.navigate(['files/' + event.value.entry.id]);
}
}
myfirstadf.component.html
<div class="mdl-grid">
<div *ngIf="viewTasks" class="mdl-cell mdl-cell--6-col task-column mdl-shadow--2dp list-column">
<activiti-tasklist
[appId]="'1'"
[state]="'open'"
[assignment]="'assignee'"
(rowClick)="taskClicked($event)"
[data]="dataColumns">
</activiti-tasklist>
</div>
<div *ngIf="viewContent" class="mdl-cell mdl-cell--6-col task-column mdl-shadow--2dp">
<alfresco-document-list
#documentList
[currentFolderId]="'-root-'"
[contextMenuActions]="true"
[contentActions]="true"
[creationMenuActions]="false"
(nodeClick)="nodeClicked($event)">
</alfresco-document-list>
</div>
</div>
Before leaving this source code, let’s study a little bit more some commands and directives, used in an example for the very first time. First of all something about the MyFirstADFComponent
component declared into the myfirstadf.component.ts
file.
As you can see from the source code, the @Input()
decorations are used before the declaration of the two properties of the class (viewTasks
and viewContent
). This is a standard Angular 2 directive when you have to manage inputs for a component. For further details about the @Input()
decoration, please refer to the official documentation.
Another interesting detail is about the dataColumns
property, used to customise the columns shown from the activiti-tasklist
component (please check the data
attribute of the activiti-tasklist
tag, into the myfirstadf.component.html
file). For further details about the ObjectDataTableAdapter
, please refer to the activiti-tasklist
documentation.
Last but not least, the two div tags of the myfirstadf.component.html
file, with the classes used to show the panels side by side (class="... list-column") and the optional view, depending on viewTasks
and viewContent
respectively (*ngIf="viewTasks"
and *ngIf="viewContent"
). For further details about the used class
attribute, please refer to the Material Design Lite official documentation and for further details about the *ngIf
directive, please refer to the Angular 2 official documentation.
myfirstadf
component in the my-adf
applicationNow that the page and the component are correctly developed, it’s time to adjust the my-adf
application accordingly. As you will see, this is something we did in the past tutorials and it is a regular Angular 2 development, done for the specific case of the my-adf
application. Below you can find the changes to do for each file.
index.ts
in <my-adf>/app/components
folder
// Add the export below.
export { MyFirstADFComponent } from './myfirstpage/myfirstadf.component';
app.module.ts
in <my-adf>/app
folder
import {
...
MyFirstADFComponent, // Add this.
...
} from './components/index';
@NgModule({
...
declarations: [
...
MyFirstADFComponent, // Add this.
...
],
...
})
export class AppModule { }
myfirstadf
in actionAfter the changes above, the new ADF component can be considered as created and correctly setup for the my-adf
application. If you stopped the my-adf
application, as suggested in the initial paragraph, now it’s the right time to start it again using npm start
from a terminal. After the starting, if you don’t have any errors or issue to solve, the myfirstpage
view should look like the picture below.
The myfirstpage
view through the myfirstadf
component.
To see how myfirstadf
works as a new ADF component, let’s edit the myfirstpage.component.html
file into the <my-adf>/app/components/myfirstpage
folder, and change the source code as described below.
<myfirstadf-component
[viewTasks]="false" <!-- Change this. -->
[viewContent]="true">
</myfirstadf-component>
Saving the file, you will see that the application will be updated automatically. Below a picture showing how the myfirstpage
view looks like after the changes.
The myfirstpage
view through the myfirstadf
component with viewTasks=false
and viewContent=true
.
As another example, let’s edit the myfirstpage.component.html
file and change the source code as described below.
<myfirstadf-component
[viewTasks]="true" <!-- Change this. -->
[viewContent]="false"> <!-- Change this. -->
</myfirstadf-component>
Saving the file, you will see that the application will be updated automatically. Below a picture showing how the myfirstpage
view looks like after the changes.
The myfirstpage
view through the myfirstadf
component with viewTasks=true
and viewContent=false
.
All the content available in this tutorial has been developed and tested using Alfresco ADF v1.1.0 LA release. Below the full list of platforms, languages, frameworks and tools used here.
Each variation to the listed versions and tools could affect the success of the tutorial, even if the involved technologies and tasks have been defined to be as more general as possible, not related to any specific context or platform. Please let us know for any issue or problem, requesting for support into the Community Portal dedicated to the Alfresco ADF or to the Gitter space dedicated to the Alfresco Angular 2 components.
In this tutorial we treated the pages and components creation into your application built using the Alfresco Application Development Framework (named also Alfresco ADF). The Alfresco ADF is provided by Alfresco as Open Source, to build custom applications on top of the Activiti BPM Engine and Alfresco ECM Repository. For further details about the Alfresco ADF, please refer to the alfresco-ng2-components GitHub Project and take a look to the Alfresco Catalog, with a friendly (and technical) overview of all the available components. For requests of support, questions and feedback, don’t forget to participate to the Community of Developers dedicated to the ADF or to the Gitter space dedicated to the Alfresco Angular 2 components.