Originally, my demo mobile application used Saxon-CE with a bit of JQuery to coordinate Ajax calls. I soon replaced JQuery with AngularJS because I wanted a chance to use this framework, and because I liked the name "AngularSaxon". Meanwhile, I was also figuring out a way to embed a Firefox OS build within an Android PhoneGap build.
It soon became apparent that Angular, at 80K, could perform many tasks faster than Saxon-CE, at 800K, and since I had both JSON and XML available, I started shifting my focus, to allow a time trial between the two wire formats. One thing I discovered is that, whereas XSLT can handle something like:
<Prescription id="2">...</Prescription>
...in the specific case where there is only one element, in JSON, this surfaces as the difference between an Array and an Object, which results in problems using Angular's ng-repeat directive. I was able to create a workaround in my JavaScript objects, as detailed below.
I had already created an Angular Service to handle rendering in both XSLT, using Saxon-CE, and in JSON. This Rendering Service already contained an exposed copy of the data returned from an API call, triggering an Angular Controller when the data is ready. I added the following method to the Rendering Service to insert an absent Array for a container element:
renderingService.fixJSONContainer =
function(parentNode, childName) {
if (parentNode !== undefined) {
var childNode = parentNode[childName]
if (!Array.isArray(childNode)) {
parentNode[childName] = new Array(childNode)
}
return parentNode[childName]
}
return []
}
This helper method is available to the Response Controller, since it has already been Dependency Injected. In the Response Controller, I made the following changes to the render method for JSON:
$scope.$on('renderJSON', function() {
$scope.fixJSONContainers(renderingService.data)
$scope.pmix.resp.prescReport = renderingService.data[...]
$scope.pmix.response.prescriptions =
$scope.pmix.resp.prescReport['pmp:Prescription']
});
$scope.fixJSONContainers = function(data) {
var prescriptionArray =
renderingService.fixJSONContainer(data[...],
'pmp:Prescription')
for (prescriptionNode in prescriptionArray) {
prescriptionDrugArray = renderingService.fixJSONContainer(
prescriptionArray[prescriptionNode],
'pmp:PrescriptionDrug')
}
}
The local method fixJSONContainers is specific to my schema, and requires intimate knowledge of the schema; where for instance, the CAM elements have makeRepeatable. Other than that, this solution is generic. In my HTML View, Angular handles the data-binding using ng-repeat directives:
<ol id="prescriptions">
<li ng-repeat="prescription in pmix.response.prescriptions">
<h3> Prescription #:
{{prescription['pmp:PrescriptionNumberText']}}
({{prescription['pmp:DrugRefillNumberCount']}})</h3>
<div ng-repeat="prescriptionDrug in
prescription['pmp:PrescriptionDrug']">
<div> Prescription:
{{prescriptionDrug['pmp:DrugProductNameText']}}
- {{prescriptionDrug['pmp:DrugStrengthText']}}
- {{prescriptionDrug['pmp:DrugUnitOfMeasureText']}}
</div>
</div>
</li>
</ol>
Once the changes have been made to the underlying Services and Controllers, the HTML View is very tight and concise, which is part of the magic of Angular. Autowired data-binding takes care of the rest.
No comments:
Post a Comment