cogDemonstration of usage of AngularJS with an XWiki backend
TypeXAR
Developed by

Ludovic Dubost

Active Installs0
Rating
Rate!
0 Votes
LicenseGNU Lesser General Public License 2.1
Installable with the Extension Manager

Description

The package as-is works only on XWiki Enterprise. To make it work on a sub-wiki of XWiki Enterprise Manager some modifications are needed in the URL of the services called by AngularJS.

This application is an XWiki developed application using XWiki App Within Minutes extended with an AngularJS developed module which copies part of the functionality of the Angular JS Tutorial.

First, you have an XWiki Application to manage the Phones. It uses the standard XWiki Livetable and XWiki features which allows to view and edit Phones in the Wiki.

angular1.png

Then an AngularJS application is directly developed in XWiki to navigate in the information stored in the Wiki. Compared to the AngularJS tutorial the data shown is stored in the XWiki content repository.

Here you can see a search which displays the list of matching phones and the detailed information about a phone:

angular2.png

Here you can see another phone information displayed with another image displayed:

angular3.png

The AngularJS code used is the following:

## the angulare XWiki macro is used. This macro will simply add the standard angularJS javascript and a div to name the application
## if css=1 then an XWiki StyleSheet extension is also automatically added to add additional CSS
{{angular app="xwiki" css="1"}}
<script type="text/javascript">
// we active the angular resource module to read JSON data
angular.module('xwiki', ['ngResource'])

// this is the controller communicating with XWiki and managing the state changes in the UI
function XWikiSearchCtrl($scope, $resource) {
   // we initialize the search term to make sure a first request is sent
   $scope.searchTerm = ""

   // this variable allows to search for the list of Phones in the wiki by matching title
   // it used the standard XWiki livetable that was created when we used XWiki App WithinMinutes to create the Phones application
   $scope.xwikiQuery = $resource('/xwiki/bin/get/Phones/PhonesLiveTableResults',
        {"doc.title":"", outputSyntax: "plain", transprefix : "phones.livetable.", classname: "Phones.PhonesClass", collist : "_image,doc.title,os,os_version,screen_size,hardware_cpu,details", offset: "1", limit: "15", reqNo: "1", sort : "doc.title", dir: "asc"},
        {get:{method:'GET'}});

   // this function is called whenever the search term changes and is also ran once at the beginning
   $scope.doSearch = function () {
       // the result of the search is saved in the xwikiQueryResult variable in the scope
       $scope.xwikiQueryResult = $scope.xwikiQuery.get({"doc.title": $scope.searchTerm});
    };

   // this method is called when a phone is clicked on in the search result
   // it will retrieve mode detailed data about the phone in XWiki
   $scope.doGet = function(docName, docDetails) {
    // we prepare the 3 backend resources we need to retrieve the data in XWiki
    // while this is not optimal and the xwiki rest api could be improved to allow to retrieve all that data in only one request, we need this for now
    // this ressource allows to retrieve the page level data
    $scope.xwikiDocQuery = $resource('/xwiki/rest/wikis/xwiki/spaces/Phones/pages/:docName',
        {docName: "", media: "json"},
        {get:{method:'GET'}});
    // this ressource allows to retrieve the phone metadata
    $scope.xwikiObjectQuery = $resource('/xwiki/rest/wikis/xwiki/spaces/Phones/pages/:docName/objects/Phones.PhonesClass/0',
        {docName: "", media: "json"},
        {get:{method:'GET'}});
    // this ressource allows to retrieve the list of images
    $scope.xwikiAttachQuery = $resource('/xwiki/rest/wikis/xwiki/spaces/Phones/pages/:docName/attachments',
        {docName: "", media: "json"},
        {get:{method:'GET'}});

    // we set the mainImageUrl to empty
    $scope.mainImageUrl = "";
    // we set the current selected phone to docName passed in parameter of doGet
    $scope.phone = docName;
    // we save details with the value of docDetails passed in parameter of doGet to allow to use that data in the Angular JS HTML
    $scope.details = docDetails;

    // we initialize the list of properties to empty and will load the data from the phone metadata into it
    $scope.properties = {};
    // we initialize the list of images to empty and will load the data from the images into it
    $scope.images = [];

    // this query retrieves the page level information. No transformation is needed as the data can be used directly in the Angular JS HTML
    $scope.doc = $scope.xwikiDocQuery.get({docName: docName});

    // this query retrieves the attachment information and we extract the list of URLs and store them in $scope.images
    $scope.attachments = $scope.xwikiAttachQuery.get({docName: docName}, function(attachments) {
       for (var i=0;i<attachments.attachments.length;i++) {
        if (i==0) {
          // we set the mainImageURL to the first image found
          $scope.mainImageUrl = attachments.attachments[i].xwikiAbsoluteUrl;
         }
         $scope.images.push(attachments.attachments[i].xwikiAbsoluteUrl);
        }
     });

    // this query retrieves the phone metadata which is not very easily exploitable. We transform the important data (value of the fields) into a simple map in $scope.properties
    $scope.object = $scope.xwikiObjectQuery.get({docName: docName}, function(object) {
     for (var i=0;i<object.properties.length;i++) {
       var property = object.properties[i];
        $scope.properties[property["name"]] = property.value          
      }
     });
    };

   // when a thumbail is clicked with change the mainImageURL
   $scope.setImage =  function(img)  {
     $scope.mainImageUrl = img;
    }
 
   // launch a first search
   $scope.doSearch();
}

//XWikiSearchCtrl.$inject = ['$scope', '$resource'];

</script>
<div ng-controller="XWikiSearchCtrl">
   <table border="0" width="100%">
   <tr><td width="20%" style="vertical-align: top;">
    <form class="form-horizontal">
        <input type="text" ng-model="searchTerm">
       <!-- here we bind the doSearch method with ng-click -->
        <button class="btn" ng-click="doSearch()"><i class="icon-search"></i>Search</button>
    </form>
    <table class="table table-striped" border="0">
       <!-- here we bind the xwikiQueryResult object from the scope -->
        <tr ng-repeat="doc in xwikiQueryResult.rows">
       <!-- here we bind the call to doGet in ng-click to launch the retreival of detailed data about a phone -->
       <!-- we also show the first image as well ad the name of the phone -->
         <td><a href="" ng-click="doGet(doc.doc_name, doc.details)" ng-bind-html-unsafe="doc._image"></a></td>
         <td><a href="" ng-click="doGet(doc.doc_name, doc.details)">{{doc.doc_title}}</a>
         </td>   
        </tr>
    </table>
    </td>
    <td ng-show="phone">
      <table>
      <tr>
       <td style="vertical-align: top;">
<!-- this image tag is bound to the mainImageURL fied -->        
        <img ng-src="{{mainImageUrl}}" class="phone">
        <br />
         <ul class="phone-thumbs">
<!-- this is bound to the list of images and will display the thumbnails -->
          <li ng-repeat="img in images">
<!-- in ng-click we call setImage to change the main image URL -->
           <img ng-src="{{img}}" ng-click="setImage(img)">
          </li>
         </ul>
       </td>
       <td style="vertical-align: top;">
        <h2>{{phone}}</h2>
<!-- the details about the phone is bound here. A special way is used as the field contains HTML -->
         <span ng-bind-html-unsafe="details"></span>
<!-- the metadata of the phone stored in $scope.properties is display using bindings -->
         <ul>
          <li>CPU: {{properties.hardware_cpu}}</li>
          <li>USB: {{properties.usb}}</li>
          <li>OS: {{properties.os}} {{properties.os_version}}</li>
          <li>Screen size: {{properties.screen_size}} inches</li>
          <li>Screen resolution: {{properties.screen_resolution}}</li>
          <li>RAM: {{properties.ram}}GB</li>
          <li>Storage: {{properties.storage}}GB</li>
          <li>Weight: {{properties.weigth}}g</li>
         </ul>
        </td>
       </tr>
      </table>
     </td>
    </tr>
   </table>
</div>
</div>
{{/angular}}

Tested on

This extension has been tested with the following configurations.

Extension VersionXWiki FlavorNotes
0.9.1XWiki Enterprise 6.0.1

Prerequisites & Installation Instructions

We recommend using the Extension Manager to install this extension (Make sure that the text "Installable with the Extension Manager" is displayed at the top right location on this page to know if this extension can be installed with the Extension Manager). Note that installing Extensions when being offline is currently not supported and you'd need to use some complex manual method.

You can also use the following manual method, which is useful if this extension cannot be installed with the Extension Manager or if you're using an old version of XWiki that doesn't have the Extension Manager:

  1. Log in the wiki with a user having Administration rights
  2. Go to the Administration page and select the Import category
  3. Follow the on-screen instructions to upload the downloaded XAR
  4. Click on the uploaded XAR and follow the instructions
  5. You'll also need to install all dependent Extensions that are not already installed in your wiki

Release Notes

v0.9.1

First version of AngularJS Demo

Tags: angularjs
Created by Ludovic Dubost on 2013/04/16 18:37
    

Get Connected