A complaint that we have heard on occasion is that it is hard to find and hire people with Aikau skills. It’s probably not unexpected that there are few people with a lot of experience in Aikau - after all it’s only really existed as a named entity for a couple of years and is specific to a single vendor in a relatively niche market of IT.
...But “skills” ?
If you have working knowledge of HTML, JavaScript and CSS then you’re pretty much halfway there. The other half of the puzzle is getting your head around 3 concepts:
It’s also vitally important to understand the problem that Aikau is trying to achieve. It is not intended to be the go-to solution for building any web application:
It is about providing a way in which a page can be defined in such a way that anyone can make small or large alterations to that page with the minimum of effort. It is about providing a way in which Alfresco can quickly iterate on its own use cases (as well as those of its partners, customers and community) in a backwards compatible way. Finally, it is about providing re-usable components to build solutions that are specifically targeted for Alfresco.
Aikau aims to decompose solutions into the smallest possible, reusable components (or widgets). Each widget is typically independent of any other in order that it can be tested as a single atomic unit.
Being able to test each widget is essential.
By defining a widget as a configurable “black box” we are able to write tests to verify how a widget behaves when configured in a certain way. We do not have to write full integration tests of how every widget interacts with every other type of widget - simply how a widget responds to publications (more on that later).
When we first started writing Aikau, there was no native module loading available (unlike now) so we used the AMD paradigm as provided by Dojo (also implemented in RequireJS). Native JavaScript imports (to the best of my knowledge) are still constrained to just JavaScript files - but some frameworks (such as Angular 2) are providing the ability to define components that reference external CSS and HTML templates (for the record, Aikau was doing this 3 years in earlier !)
Although it is the Surf framework that handles the CSS, HTML (and i18n) dependency loading it is the Aikau widget that defines the dependencies. When creating an Aikau widget you simply need to understand how these dependencies can be declared.
It’s important to be able to recognize the “boiler plate” of an Aikau widget. This is the most simple example of a widget that defines HTML, CSS and i18n dependencies.
define(['dojo/_base/declare',
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dojo/text!./templates/MyWidget.html',
'alfresco/core/Core'],
function(declare, _WidgetBase, _TemplatedMixin, template, AlfCore) {
return declare([_WidgetBase, _TemplatedMixin, AlfCore], {
i18nRequirements: [{i18nFile: './i18n/MyWidget.properties'}],
cssRequirements: [{cssFile:'./css/MyWidget.css'}],
templateString: template,
postCreate: function() {
// TODO Put your code here
}
});
});
All your code (any JavaScript you like) should go into the postCreate function.
Let’s say that you don’t want an external template and have no CSS or i18n dependencies. This reduces the basic widget to this:
define(['dojo/_base/declare',
'dijit/_WidgetBase',
'alfresco/core/Core'],
function(declare, _WidgetBase, AlfCore) {
return declare([_WidgetBase, AlfCore], {
buildRendering: function() {
// TODO: Create some HTML for the widget and assign to this.domNode
},
postCreate: function() {
// TODO Put your code here
}
});
});
The buildRendering function should be implemented to construct the DOM for the widget - again, using any JavaScript that you’d like.
The buildRendering and postCreate functions are part of the Dojo widget life-cycle that Aikau make use of. It is necessary to extend “dijit/_WidgetBase” and to use the define and declare functions when writing a widget - but literally everything else your widget does is entirely up to you. We just happen to use a lot of other Dojo capabilities because we find them useful - whether or not you choose to is entirely up you.
But there is no magic here - it is just JavaScript.
The define function tells the AMD loader what modules to load, the declare function creates the JavaScript Class. The buildRendering and postCreate functions are called when an instance of the class is created. A more in-depth description of widget creation can be found here.
In order to make it possible for a page to be easily customized it is essential that the building blocks of that page (the widgets) be completely decoupled from one another. This is where the publication/subscription model comes in.
It would undoubtedly be much easier to implement a solution where there are fixed references between widgets, but that would greatly constrain what a 3rd party could do a page.
Instead Aikau widgets communicate with one another by publishing requests on topics and subscribing (or listening) to and responding to other requests that are published.
In order to ensure that communications between widgets can be constrained to a subset of widgets it is possible to define a scope. This allows one group of widgets that share a common topic type to communicate with each other without impacting another group of widgets.
Imagine a scenario where you have two lists on the page each with their own sorting controls - changing the a sort order in one list should not update the order of the other list. This is where scoping comes in.
A publication/subscription scope is set on a widget by setting its “pubSubScope” attribute with a string value. This value is prefixed onto all topics published and only topics prefixed with that value are subscribed to.
The “pubSubScope” attribute is one of a handful of attributes that is passed down from parent widget to child widget. A child will have the same scope as its parent unless specifically configured otherwise.
As well as being decoupled from each other via the publication/subscription model, widgets are also decoupled from data. This allows a widget to work with multiple data sources - so for example the “alfresco/lists/AlfList” widget can be used to render any list - documents, sites, people, properties, aspects, etc. All data should be accessed via a service.
Services in Aikau can be considered the glue that binds the page together. They can perform a number of roles as well as handling XHR requests - the “alfresco/services/DialogService” for example is purely responsible for the creation and management of modal dialogs. If you don’t like the default dialogs in Aikau then an alternative service can be used instead - widgets don’t “care” what services their request for a dialog, only that it is serviced.
The most common role of a service though is to make asynchronous (XHR) requests for data from the Alfresco Repository. A widget will publish a request for some data on a specific topic and if a service exists that subscribes to that topic then it will process that request, retrieve the requested data from the Alfresco repository and return it to the widget on the requested response topic.
Dipping back very briefly into the subject of publication/subscription scoping…. Services are typically not scoped. However, in order that widgets are able to communicate with them all publication configuration can include an option to publish “globally” - or without scope. This ensures that it is not necessary to have instances of services at every scope used by widgets on the page.
An Aikau page is declared as a model in a WebScript JavaScript controller. I typically describe this as a JSON model and am frequently criticized by my colleagues for describing it as such because in the WebScript controller you are technically creating a JavaScript Object Literal - but on it’s way to being processed by Surf it does get converted into JSON, so I’m going to keep calling it JSON.
The structure of the model in your JavaScript controller should look like this:
model.jsonModel = {
services: [],
widgets: []
};
...services and widgets being added into the appropriate arrays.
The “widgets” model will typically become a deeply nested tree with widgets placed inside other widgets.
By constructing a page like this is means two things:
The disadvantage of this approach is that for simplicity you normally have to rely on the various widgets in the “alfresco/layout” package to build the structure of your page rather than just using HTML/CSS.
However it is possible to embed Aikau into any DOM node on the page by including a “rootNodeId” attribute in your model. This would allow you to construct the layout for your page in your WebScript template using HTML into which the Aikau model could be built.
It’s also possible to have multiple Aikau models embedded into different locations on the page - the best approach for this would be to use the standard Surf region/component development approach. Effectively this is what you see on most pages in Share - the header is a Surf Component rendering an Aikau model and the remainder of the page is made up of other Surf Components rendering YUI2.
Aikau is really just a way of packaging HTML, CSS and JavaScript into reusable modules. It isn’t a new language, but is merely a new way of thinking about web development. This approach has its advantages (reuse, extensibility, customization, dynamic page creation) but also has its drawbacks (requires a different way of thinking, is a layer of abstraction away from traditional web development).
It’s not a framework for any use case - it’s targeted specifically for Alfresco development and depending upon your specific use case it may or may not be the right choice for you. It is worth remembering that unless we know your use cases we’ll never be able to address them - so if there’s something you’d like Aikau to do better then please let us know!