2 - Get a Document
Reset the workspace to step 2:
git checkout -f step-2
This steps adds a link to each document in the list, linking to a page rendering some of the document's content.
The Document Detail Resource
As you have seen in the previous step the content of a particular document can be accessed by appending that document's ID to the Document Detail resource's URL:
http://localhost:8080/site/api/documents/[id]
For example:
http://localhost:8080/site/api/documents/b8f5eb45-7200-452a-b26e-3118a0dc60b8
The response consists of a JSON object containing a number of meta properties as well as the properties holding the actual content (as defined by the document's type). The example below shows a document breakfast of type myhippoproject:eventsdocument. Some of its content properties include a title, a date, an end date, a location, an introduction and some rich text content.
{ "id":"b8f5eb45-7200-452a-b26e-3118a0dc60b8", "name":"breakfast", "displayName":"Breakfast", "type":"myhippoproject:eventsdocument", "locale":"en", "pubState":"published", "pubwfCreationDate":"2013-11-12T11:00:00.000+01:00", "pubwfLastModificationDate":"2016-01-26T14:27:32.597+01:00", "pubwfPublicationDate":"2016-01-26T14:27:34.348+01:00", "items":{ "myhippoproject:enddate":"2017-01-26T13:19:00.000+01:00", "myhippoproject:location":"Room 101", "myhippoproject:title":"Breakfast", "myhippoproject:date":"2013-11-12T08:00:00.000+01:00", "myhippoproject:introduction":"Start the day with a nice breakfast.", "myhippoproject:content":{ "type":"hippostd:html", "content":"<p>Breakfast is served starting from 8:00 until 9:30.</p>" }, "myhippoproject:image":{ "type":"hippogallerypicker:imagelink", "link":{ "type":"binary", "url":"http://localhost:8080/site/binaries/content/gallery/myhippoproject/samples/coffee-206142_150.jpg" } } } }
Note that the document's type, as well as the document's actual content properties, are namespaced. Namespaces prevent different document types from having naming conflicts. When referring to a document type or a document property in Bloomreach Experience Manager it must always be prepended by its namespace's prefix and a colon, e.g. myhippoproject:eventsdocument or myhippoproject:title.
Also note that the rich text content (items['myhippoproject:content'].content) consists of an HTML string.
Code Changes
Dependencies
A dependency to ngSanatize is added to the app in order to be able to sanitize (i.e. strip any dangerous or unwanted tokens from) the HTML content.
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-sanitize.js"></script>
app.js
var hippoRestApp = angular.module('hippoRestApp', [ 'ngRoute', 'ngResource', 'ngSanitize' ]);
DocumentsService
The DocumentsService is extended with a getDocumentById function which uses the $resource service to retrieve the content for a particular document from the Document Detail resource as explained above.
app.js
hippoRestApp.factory('DocumentsService', function($resource, apiPrefix) { return { getList : function() { return $resource(apiPrefix + 'documents/', {}).get(); }, getDocumentById : function(uuid) { return $resource(apiPrefix + 'documents/' + uuid).get(); } } });
DocumentsController
The DocumentsController is extended so it retrieves either the documents list or an individual document's content, depending on the routing parameters. The responses are added to the scope so the views can render the content.
app.js
hippoRestApp.controller('DocumentsController', function($scope, $routeParams, DocumentsService, apiPrefix) { if (!$routeParams.uuid) { DocumentsService.getList().$promise.then(function(response) { $scope.documents = response; }); } else { DocumentsService.getDocumentById($routeParams.uuid).$promise.then(function( response) { $scope.document = response; }); } });
Views and Routing
A new detail view is added which renders a document's title, introduction and rich text content (the News, Event and Simple Content document types have these properties in common). The rich text content is inserted into the view using the ngBindHtml directive so it is automatically sanitized.
Routing is added to map the new detail view to URLs using the uuid routing parameter.
Finally, links to the detail view are added to the list items in the documents-list view.
detail.html
<div> <h1>{{document.items['myhippoproject:title']}}</h1> <p>{{document.items['myhippoproject:introduction']}}</p> <div ng-bind-html="document.items['myhippoproject:content'].content"></div> </div>
app.js
hippoRestApp.config(function($routeProvider) { $routeProvider.when('/', { templateUrl : 'document-list.html', controller : 'DocumentsController' }).when('/:uuid', { templateUrl : 'detail.html', controller : 'DocumentsController' }).otherwise('/'); });
documents-list.html
<h2>Documents</h2> <ul> <li ng-repeat="document in documents.items"><a href="#/{{document.id}}">{{document.name}}</a></li> </ul>
Experiments
- Use Bloomreach Experience Manager to edit one of the documents and create a link to another document inside the rich text field. Check if the link works in the app. It doesn't because Bloomreach Experience Manager is unaware of what frontend application might render the content, it is therefore up to the frontend application to resolve internal links in the content. This will be done in the next step.
Summary
In this step the app was extended with pages rendering individual document's content. Now go to step 3 to learn how to handle links between documents.