There is a good example of what you can do with HABPanel and a specially designed external controller.
Doing it directly in HABPanel rather than a separate web page means you can directly use AngularJS and other frameworks and controls at your disposal.
Fetching the results of a REST API and displaying a list of results with pagination suddenly becomes not so hard
Your best resources to learn would be:
- this thread: HABPanel Development & Advanced Features: Start Here! notably the Advanced: Injecting custom JavaScript code section;
- the W3Schools lessons about AngularJS, especially this one about the $http service with its interactive exercises.
Since it’s a good textbook case that could serve as an example I’ll guide you on the right track:
This would be your AngularJS controller for your widget - put it in conf/html/turku.controller.js. It loads the data and puts it in its scope along with some pagination data:
angular
.module('app.widgets')
.controller('TurkuEventsController', function ($http, $scope, $filter) {
var baseUrl = 'https://api.turku.fi/linkedevents/v1/event/?keyword=childfamilies&end=today&start=today&include=location&format=json';
// this scope function retrieves the current page (in $scope.currentPage) from the API
$scope.loadData = function () {
// append the page parameter to the base url
var url = baseUrl + '&page=' + $scope.pagination.currentPage;
// get the data and put in the scope
$http.get(url).then(function (response) {
$scope.events = response.data.data;
// also store the number of items for the pagination control
$scope.pagination.totalItems = response.data.meta.count;
});
};
// put the current time in the scope for easy comparison in the template
$scope.now = $filter('date')(new Date(), 'yyyy-MM-ddTHH:mm:ssZ');
// initialize the pagination object
$scope.pagination = {
totalItems: 0,
currentPage: 1
};
// fetch the first page
$scope.loadData();
});
Next create a template widget and put this code:
<div oc-lazy-load="'/static/turku.controller.js'" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;">
<div ng-controller="TurkuEventsController">
<ul ng-if="pagination.totalItems" uib-pagination
total-items="pagination.totalItems" items-per-page="20"
ng-model="pagination.currentPage" ng-change="loadData()"></ul>
<uib-accordion close-others="true"
style="text-align: left; color: black;
position: absolute; bottom: 10px; right: 10px; top: 60px; left: 10px;
overflow: auto">
<div uib-accordion-group
class="panel-default"
ng-repeat="event in events"
ng-if="event.end_time >= now && event.sub_events.length == 0"
heading="{{event.start_time | date:'short'}} - {{ event.end_time | date:'short'}}: {{event.name.fi || event.name.sv}}">
<img ng-if="event.images.length > 0" ng-src="{{event.images[0].url}}" class="pull-right" style="height: 200px"></img>
<div ng-bind-html="event.description.fi || event.description.sv"></div>
</div>
</uib-accordion>
</div>
</div>
Note how I lazy-loaded the controller on the first line, assigned it to the inner part of the widget using ng-controller
, and leveraged ui-bootstrap’s pagination control to do the heavy lifting for the paging stuff and accordions with ng-repeat="event in events"
to present the data in a fancy list. The ng-change="loadData()"
on the pagination control ensures the data for the appropriate page is retrieved from the API when the page is changed.
The end result after less than one hour is what you’d expect and may not be exactly what you want, but it’s a start:
You can iterate upon this, bonus points if you create a separate post for your widget and include the widgetgallery tag to display it in the widget gallery
Good luck!