Used Technologies
Client part: Ext JS is a JavaScript library for building web applications and user interfaces. It supports AJAX technology, animation, working with DOM, implementation of grids, tabs, events handling.
Server part: Alfresco – an integrated content management system for organizations. Alfresco combines a server and a database. It uses both standard Alfresco objects and custom ones (with advanced features/possibilities). Communication between client and server is performed by means of REST services.
Application Architecture
The figure below shows a diagram of the interaction between Alfresco and Ext JS. In particular, interaction between MVC Ext JS and Alfresco.
Application Example
An application that displays a list of books (a table) that can be filtered.
Model
The define method of the Ext object allows defining the class. The first parameter is the class name. It consists of the namespace name, the directory in which the class is located, and the class name. The second parameter is the object describing the model which is being created.
Each new model should extend from the standard Ext JS model. The extent field is responsible for extending. In order to extend from the Ext JS model, in the extent field we should specify the name of the model from which we want to extend. In this case, it is Ext.data.Model.
The idProperty field allows us to specify the field whose value will be an identifier for this model. In this case, we specify the id field as an identifier.
The fields array contains the description of these model fields. Each field description is an object with the following fields:
- name – field name, it should not be duplicated within one model;
- type – type of value stored in this field, it can be auto, int, double, boolean;
- mapping – is used when receiving data from a server in the form of a complex XML. The field value is a selector that describes the node from which the value should be taken and placed in this field.
Store
At the next step, we should define the store object. The store acts as a container and is responsible for storing records in the form of objects of a certain model.
The model field contains the name of the model class whose objects will be stored in this store.
The requirements array describes the classes which should be imported into this class.
The autoLoad variable is a Boolean variable and is responsible for automatic loading of records from the server. In this case, it is set as true – it means that the data will be loaded automatically immediately after the app starts. The proxy object is responsible for receiving data from the server.
The type field defines the proxy type, in this case, we use ajax proxy. The url field of the proxy object specifies the path to which a request to retrieve data will be sent, in this case, it is the Alfresco REST service URL. The timeout field specifies the interval of server response waiting in milliseconds.
The proxy object should contain a field describing the reader object. The reader object is used for parsing the server response which is received by the proxy object. The reader object contains the root field, which specifies the name of the root node where records should be searched for. The record field specifies the name of the node which will be interpreted as a record, readed by the reader object, and added to the current store as a model instance.
Reader
When using Alfresco REST API, we receive all responses as a complex XML containing several namespaces. This raises the problem of cross-browser compatibility, not all browsers are equally able to work with namespaces. In order to solve this problem, we will write our own reader which will remove namespace prefixes in the XML prior to starting its parsing.
To do that, we extend from the standard XML reader and redefine its read method, which is called before parsing begins. In it we implement removing namespace prefixes in the XML.
View
Now we proceed to writing the view for displaying data from the store:
Each new view should extend from the standard Ext JS. This is handled by the extend field. In this property we write Ext.panel.Panel.
The alias property is a list of short aliases for class names. In this property we set the id for our panel. To make the panel available in another component or place it on the main layout we need to write:
The title property is the name of our panel.
For the panel we use the layout named layout. We use the fit layout. When the fit layout is used, the internal items are extended to the borders of the parent container.
The flex property is the width of our panel. We write 1 to extend the panel to the full length of the parent container.
The initComponent method is an important initialization step for components. It is used to implement each subclass of nested components.
The items property contains internal items. The xtype property provides a shorter alternative of objects creating than when using the full class name.
This is how a text field component is created:
This is how it looks like when using xtype:
Our panel will have the grid component. When we create the panel, the grid constructor is called and this component’s properties are set.
We create the grid component where books will be displayed. In xtype we write grid. Grid is a standard ExtJS component. Id is the unique identifier of this component. In the store property we specify the required store for displaying the data source. In viewConfig we specify the properties which will be applied to the grid. We disable the icon that displays changing of data in the grid. Also, we disable the grid loading icon.
In the column property we define the columns which will be displayed in the grid:
- text – column name;
- dataIndex – the value whose data is taken from the store;
- flex – column width.
Other properties, events and methods related to the grid component can be found here. The description of the View component of the filter panel is given in the figure below.
Controller – List Filtering
Let’s create a controller which will filter the list of books by title:
First, we extend from the Ext.app.Controller class and set the previously created views for the controller in the view’s property.
Then in the init function, which is called during controller initialization, we initialize the button handlers that we have in our view. The control function helps to link handlers to components. This function allows us to find an item using the CSS selector. Each such item is associated with an object, whose key is the event name, and the value is the event handler.
Connecting MVC
One last thing to be done is to enable all the classes in the main class app.js. We import the created store, model, controller, and view.
The main sections are name, appFolder, stores, models, controller, view, and the launch function.
In the name section we specify the name of our project – it will act as a namespace. In appFolder we specify the folder which contains the project hierarchy structure (controller, store, model, view).
In the corresponding stores, models, controller, view sections we specify the path to the created classes.
The launch function will be executed after loading all classes specified in the corresponding sections. In it we create the main layout and place our view components.
In our example, the namespace is example. The root folder is app. In the stores, models, controllers, views sections we add the previously written files.
In the launch function we create the main viewport, where the panel with the grid and the filter panel will be located. We use the Ext.create function and create a standard viewport. In the constructor we describe the layout. The layout:’border‘ value sets the layout. The border allows us to attach items to one of the four sides of the window or dock it in the center. Then we set the panels that border on the certain sides of the container using the region parameter. This parameter can have the following values:
- center – the item is placed in the center;
- north – the item is attached to the upper border of the container (“to the North”);
- south – the item is attached to the lower border of the container;
- west – the item is attached to the left side of the container;
- east – the item is attached to the right side of the container.
In the item’s property we place two panels. We place the right panel on the left side and add the filter panel inside it. The second panel is placed in the center, and we add a panel with the grid inside it.
After that, on the index.html page we need to add all required css and javascript files.
First, add the ext-all.css styles of the Ext JS library. Then, add JavaScript libraries extjs-all.js. After that, add the JavaScript file with the required localization ext-lang-ru.js. After the main imports, we add the JavaScript file of our app.js application. If you have a different application entry point JavaScript file, add it.
Application Deploy
To start the application, we need to add it to Alfresco Tomcat. First of all we stop Alfresco. The Alfresco installation package contains Manager Tools program. There we click on Stop All.
After that, we add our application WAR file to the Alfresco\tomcat\webapps\ folder and click on Restart All in Manager Tools. The app will be available at:
localhost:port/application_name/index.html
port – the port specified when installing Alfresco. By default it is 8080;
application_name – the application name specified in the WAR file.
If there is no WAR file, we can create a folder. For example, the example folder in Alfresco\tomcat\webapps\, and put the application files in it:
Then the application will be available at the address:
http://localhost:port/example/index.html
We go to Alfresco (http://localhost:port/share). Create the test example site. In the documents library we create the books folder:
In the books folder we create the Master and Margarita folder and change its type to books:
Also, we create two more folders and change their type to books. After that, for each folder, in properties we complete the initial price and publishing date fields.
Let’s go to our app. We have the app which displays the list of books and filters them by title:
Let’s check the filter work. Write “master” in the title field and apply filtering. We see that only one entry is left in the table: