Creating custom pages and components (ADF 105)

cancel
Showing results for 
Search instead for 
Did you mean: 

Creating custom pages and components (ADF 105)

alfresco
Alfresco Employee
3 0 6,670

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.

Creating your first page into an ADF application

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:

  • Use the new page, linked from the menu of the my-adf application.

Below a paragraph detailing each development with further details.

Creating the MyFirstPageComponent to manage the view

As 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.

Including the MyFirstPageComponent into the root module

To 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.

Using the myfirstpage into the my-adf application

Now 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.

Adding the ADF components

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.

Navigating between the pages

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.

About creating components for ADF

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.

Cleaning the myadfpage view

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.

Creating the myfirstadf component

In 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.

Including the myfirstadf component in the my-adf application

Now 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 { }


The myfirstadf in action

After 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.

Disclaimer

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.

  • Linux Ubuntu 16.04.01 LTS as Operating System.
  • Alfresco Community Edition 201612 GA release for Linux (running on port 8080).
  • Activiti Enterprise Edition 1.5.2.1 release for Linux (running on port 9999).
  • Node.js version 6.9.4.

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.

Conclusion

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.