Showing posts with label Angular. Show all posts
Showing posts with label Angular. Show all posts

Friday, June 05, 2015

My jsFiddle Bag of Tricks

I'm just going to say it, I love jsFiddle.net. Like others pastebins such as Gist or CodePen.io, jsFiddle allows you to rapidly prototype HTML/JavaScript/CSS and test the result in real time. There is extensive library support, and you can do tricky things like embed your results as an iframe on a GitHub page, or use GitHub to back up a demo. But the basics of jsFiddle are that you can create a small to medium application, share it easily so others can fork it, and tweak it to your heart's content, with easy to use restful routing and version control. What's not to love?

In order to make the most of jsFiddle, however, I had to sort out a few things. Please feel free to share your own bag of tricks, and here are some of mine.
  1. Use the Ionic bundle as an External Resource. You can select AngularJS 1.2 from Frameworks and Extensions, but if you add the following links to External Resource, you will get a bundle containing both AngularJS and the Ionic Framework, which allows you to do some clean mobile UI.

    http://code.ionicframework.com/1.0.0-beta.6/js/ionic.bundle.js
    http://code.ionicframework.com/1.0.0-beta.6/css/ionic.css


    You may strip out the Ionic stuff before you release your work, but I have found it to be a great framework for rapid prototyping with a Mobile First mindset. Cards are great. Also, ngCordova is an extension for Ionic which allows you to embed your work into iOS or Android using PhoneGap.
    Ionic may not be perfect (it's still in beta), but it is very Mobile First, useful for rapid development, and has a lot of similarities with Bootstrap. Try it out.
  2. Embedded results pages are great, but they often fail to load until you change "https" to "http". Same goes for the External Resources. Get used to quietly deleting the "s" during demos, and hoping that nobody notices.
    GitHub and jsFiddle can work very well together. I suspect you could get similar results with Gist or Codepen, but I personally prefer jsFiddle. Learn to use social repositories to create individual code samples and project pages.
  3. JSONP can work, this is very handy. I often set up JSONP files, JSON wrapped in a function call, on a GH Page on GitHub, so that I can access them later as though they were an actual API. In order to do so, rather than echoing the call from the jsFiddle itself, I have a useful Angular directive I use:

    rhizomeBase.factory('jsonpService', function ($http) {
        var svc = {}, jsonp_data   
        jsonp = function(data) {
            jsonp_data = data
        }
    
        svc.getData = function(callback, url) {
            $http({
                method: "JSONP",
                params: {
                    input: "GM",
                    callback: "jsonp"
                },
                url: url,
                isArray: true
            }).success(function(data, status) {
                callback(jsonp_data)
            }).error(function(data, status) {
                callback(jsonp_data)
            });
        };
        
        return svc
    });

    All this service does is set up an http: request as a promise, and then apply a callback whether the request succeeds or fails. It turns out that when the request succeeds, jsFiddle treats this as a failure, but all of this gets hidden in the service. In practice, once you have an Angular application set up in jsFiddle, you can call inject the service into your controller or directive and invoke it with a very direct call like this:
    jsonpService.getData(function(data) {
        alert(JSON.stringify(data))
    }, url)
    One of the things a pastebin allows you to do is prototype a client application without having to worry about building a server-side API first. Hosting a handful of sample messages on GitHub is a good way to accomplish this.
  4. Use appropriate standards. This is really the flip side of  building a client-side application first. If you have access to a JSON-based standard like NIEM, or you can use a snippet gleaned from Schema.org, this will save you some design time and get you moving in a forward trajectory. In my case, the JSON flavour of HL7 FHIR, the component-based nature of Angular, and the ease of use and built in UX touches of Ionic are a perfect storm for the kind of work I like to do, and jsFiddle is the glue that holds these together.
    If you can, learn and use appropriate standards.

Sunday, January 04, 2015

Using AngularJS with HL7 FHIR Questionnaire

This  is a very simple example using Angular templating (no directives) with an HL7 FHIR Questionnaire resource, which I am using directly from one of the public FHIR servers (Grahame's to be precise). In addition to the machine-readable content for question groups and answers, I am creating a rudimentary service to manage coded concepts (ie value sets), and I am displaying the human-readable portion of the resource (the HTML text div) as well. This is really just a beginning, and one thing I would like to build into this demonstration is the ability to use embedded SVG for the human-readable portion, as it seems to me that existing PDF questionnaires could be converted to SVG and thus embedded. Makes for a large resource file, but this would be a great way to retain the look and feel of existing documents, once an easing library is used to zoom in on the appropriate area of the SVG. I'm calling this demonstration "QuestionCare" because I think it would also be useful to be able to use Careplan within this context.

We begin with a root HTML that sets up my Single Page Application, and a reference to my Rhizome library, which contains a number of useful client-side services:
<body id="content" style="display: none;" ng-app="questioncare">
      <h3 ng-controller="ErrorController" ng-bind="errorText" ng-show="showError"></h3>
      <div id="request" ng-controller="RequestController">
        <button id="view-questionnaire" ng-click= "viewQuestionnaire()">View Questionnaire</button>
      </div>
      <ng-include src="res/templates/Questionnaire.html"> </ng-include>

This corresponds to a single line in the javascript initialization:
var questioncare = angular.module('questioncare', ['rhizome', 'ngSanitize']);
 We'll see how the ngSanitize module is required in order to handle rendering the human-readable HTML div from the Questionnaire resource as HTML, instead of text, using ng-bind-html. In any case, we are setting up a controller to handle a request, and then we are including a template to handle the response. The rest, as we shall see is handled through controller code and client-side services, but let's take a quick look at the included template for Questionnaire:
<div id="questionnaireResponse" ng-controller="QuestionnaireController" ng-show="showQuestionnaire">
  <div ng-bind-html="humanReadable"></div>     <hr/>
  <div ng-bind="questionnaire.name.text"></div>
  <div ng-bind="group.header"></div>
  <hr/>
  <ol id="questions">
    <li ng-repeat="question in group.question">
      <div ng-bind="question.text"></div>
      <ol id="options">
        <li ng-repeat="option in getOptions(question.options.reference)">                    [<span ng-bind="option.code"></span>]:
      <span ng-bind="option.display"></span>
        </li>
      </ol>
    </li>
  </ol>
</div>
 That takes care of the HTML. The request controller invokes an adapter (this is running on IBM Worklight), and then sends the response to the questionnaire controller using $rootScope.broadcast, but first it calls a client-side service which I have made responsible for managing codes; in this case, the value sets for the different options you can pick when you answer the questionnaire.
questioncare.controller( 'RequestController',
  function($scope, $http, $rootScope, errorService, codeService) {

    $scope.viewQuestionnaire = function() {
           
      var invocationData = {
        adapter: 'FHIR',
        procedure: 'getQuestionnaire',
        parameters: []
      };
           
      WL.Client.invokeProcedure(invocationData, {
        onSuccess : function(result) {
          if (200 == result.status) {
            var ir = result.invocationResult;
            if (true == ir.isSuccessful) {
              $scope.$apply(function () {
                var questRes = ir.content;
      codeService.loadCodedConcepts(questRes.contained);          $rootScope.$broadcast('qr', questRes);
              });
            } else {
      errorService.worklightError('Bad Request');
            };
          } else {
      errorService.worklightError('Http Failure ' + result.status);
        };
      },
      onFailure : errorService.worklightError
    });
  }
});
The codeService itself is quite simple, although, since value sets could potentially come from a variety of places, this service could become a lot more complicated. In this case, I am just scraping contained value sets from the Questionnaire resource itself:
rhizome.factory('codeService', function($rootScope, errorService) {
  var codeService = {};
  codeService.codedConcept = Object;
   
  codeService.loadCodedConcepts = function(contained) {
    for (c in contained) {
      codeService.codedConcept[contained[c].id] = contained[c].define.concept;
    }
  };
   
  codeService.getCodedConcept = function(opt, remHash) {
    if (remHash) {
      opt = opt.substr(1);
    }
    return(codeService.codedConcept[opt]);          
  };
   
  return codeService;
});    
Angular services can be difficult to grasp at first, but they are one of the more important features of the framework, since they allow you to make your client-side more portable and standardized; however, this particular service is little more than a stub at this point. It deals with a hash sign which is probably included with the value set id, which is useful. Once the coded concepts have been scraped out of the Questionnaire, the document is displayed using the included template and a response controller.
questioncare.controller( 'QuestionnaireController',
  function($scope, errorService, codeService) {
   
    $scope.showQuestionnaire = false;
   
    $scope.$on('qr', function (event, arg) {
      $scope.questionnaire = arg;
      $scope.group = $scope.questionnaire.group;
      $scope.humanReadable = $scope.questionnaire.text.div;
      $scope.showQuestionnaire = true;
    });
          
    $scope.getOptions = function(opt) {
      return codeService.getCodedConcept(opt, true);
    };

});
Again, there is nothing too complicated here. Notice how the humanReadable questionnaire text div gets bound into an element that allows HTML to be rendered. Also, a second function is used to get and then display the options because these need to be repeated, as you can see in the Questionnaire.html. In addition, the entire questionnaire template is hidden until it is populated.

Next steps here will be to work with nested questionnaires, where selected options will traverse through a hierarchy of question groups. At this point, it may be useful to use Angular custom directives, although I am also trying to be careful about anything that will be subject to change with Angular 2.0, such as controllers.

More and more as I work with Angular, Worklight and HL7 FHIR, it strikes me that what is important here is building a library of standard services and templates on the client side, and then simply binding into it. Once DSTU2 is complete for FHIR it will become less of a moving target, but resources like Questionnaire, which has been the subject of several connect-a-thons now, seem especially stable.

Monday, December 29, 2014

Atomized Integration, IBM Worklight and AngularJS

Over the past year, I have worked fairly extensively with IBM Worklight, Big Blue's enterprise mobility package. In the coming year, I plan to find more things to do with Bluemix, IBM's cloud mashup line; for now, some thoughts.


In general, my guidance has been to use open source mobility frameworks, PhoneGap for cross-platform, Bootstrap for Responsive Web Design, Angular for templating, and some form of OAuth2 for security, at least until the vendor solutions from IBM, Oracle, et al reach a higher level of maturity, since these are stepping stones.

If you look at the latest Gartner quadrants for enterprise mobility and cloud for the previous year, you will see IBM maturing in the MADP space and Oracle maturing in the cloud space... but maturity in both areas is necessary for enterprise mobility to fire on all pistons.

Worklight does three things really well:
  1. Simple adaptation on the server-side, using Rhino-based Javascript adapters.
  2. Integrating with existing Websphere and SAM infrastructure.
  3. Increasing productivity through modularization and emulation.
Probably the biggest win here is 3. I started out 2014 working with Firefox OS, Saxon-CE and AngularJS, so I was already committed to using Javascript and XSL as much as possible, and Worklight Adapters played into this approach nicely; however, after *hating* the slowness of native Android development using the Android toolkit, what I appreciated most about Worklight was being able to use an emulator that ran as smoothly as the Firefox OS simulator (which is really just a browser plugin). On the server-side, we are becoming more accustomed to devOps tools like JRebel; on the client-side, we should have similar expectations - is, don't use the Android emulator if you can avoid it. It sucks.

I have mentioned previously how much I like Worklight's lightweight Rhino-based adapters. They are intentionally lightweight, eschewing any sort of SOA reusability. A Worklight adapter does one thing, and it does it well. This can be initially quite pleasant, then very frustrating, and then liberating, as you sort out how much integration you need to do in your client applications. My experience has been that a well designed piece of XSL can convert an XML data source into some standards-compliant JSON, and then a client-side library service can take it from there.

For instance, consider that I have an XML data source containing a number of patient records. Let's say it is NIEM compliant XML. I could build a client application that can consume NIEM compliant JSON, and then all I would need to do in Worklight is create a very simple boilerplate adapter that transforms the XML into JSON. This is assuming that my server-side data source doesn't already support JSON-flavoured NIEM, which would be even simpler. In other words, if my intent is to take a NIEM compliant data source and build a NIEM compliant mobile application, this is quite straightforward. Server-side Worklight adaptation transforms XML into JSON; client-side Angular data-binding injects JSON into the HTML-based presentation layer, and presto, you have an application.

Granted, the development process is not that easy, and let's consider now that we have a number of data sources, some of which are NIEM compliant, some of which are HL7 compliant, some of which are based on direct SQL access, and some of which are ad hoc.

When you look at the various Worklight adaptation examples, you might get the idea that RSS is treated preferentially, which is untrue; however, thinking of these adapters as syndication is still a useful approach.

Throughout the past year, I have been working with HL7 FHIR, a draft standard from HL7 that among other things introduces a JSON-based pattern for aggregation and composition that is essentially Atom syndication in JSON instead of XML. It turns out that if all of my Worklight adapters create Atom-compliant JSON on the server-side, then I can use a Javascript Atom library in the client, and it really doesn't matter what format my data sources are using. By the time they reach my client application, they are all Atom-based.

The client-side service that I have written - using Angular for modularization - is responsible for merging multiple Atom streams. Once I have a single Atom stream, data-binding takes place, so that information can be presented. In practice, this can be frustrating because Atom is intended for serialization of information, but an Atom bundle can also contain relative links between entries. This is fundamental to the way HL7 FHIR works, but not NIEM, so I have ended up creating synthetic and essentially schemaless resources as necessary. Ideally, all information could be mapped into Atom-syndicated FHIR resources. Maybe that's a good project for this year.

Adaptation frameworks always run into a problem based around the decision to go lightweight or go modular. I like that Worklight has gone lightweight, but I am frustrated that I can't reuse just a little bit more code between adapters. In particular, I would really like to use a single set of XSL transforms to support multiple adapters. Perhaps there is a way to do this, but for now, I am still forcing myself to prune my adaptation code as much as possible to keep it easy to maintain. If I find myself using the full set of DocBook or DITA transforms in an adapter, it's probably time to rethink my approach.

On the whole, I have enjoyed working with Worklight adapters immensely; I don't think this would be the case if I was not also using Angular or some other Javascript framework to support development of client-side services. I haven't particularly used the built-in Worklight support for Dojo or JQuery, but I'd go so far as to say that without some sort of hybrid framework support, you will lose much of the productivity that Worklight gives you. After a year, I have reached an understanding that I would not enjoy using a framework like Angular without a platform like Worklight, and I would not enjoy using a platform like Worklight without a framework like Angular.

Unless, of course, the platform was also a framework, which is what approaches like Meteor promise. 

  

Thursday, August 14, 2014

AngularJS and Durandal

When I read on the Angular blog that Rob Eisenberg is working with Angular in addition to continuing revisions on the Durandal templating library, I was understandably excited. I have really enjoyed working with Angular, not just as an SPA framework, but as a prescriptive, modular, and mature JavaScript framework, but like many people, I have found custom directives frustrating; jsFiddle and similar tools provide a good way to develop and test a new directive in isolation, but still. I've experienced this on other projects, using Adobe Flex, for instance. On a project team, you have a number of developers, one of whom supports custom web components, and that works okay, but the other developers don't really understand how the components work under the hood.

I am hoping that the next evolution of AngularJS (3.0) will align much more closely with Durandal, Web Components API, and Polymer. There is really no reason why custom Web Components cannot become just a standard practice for the web. And that's nothing like Angular custom directives, which are confusing, I think, because whereas in most cases Angular balances flexibility and prescription nicely, custom directives are incredibly flexible - transclude? allow directive through attribution or class, or just elements? and so forth. Custom directives are just way too flexible, and they need to be a simple API for doing one thing well, not a combinatorics problem.

On the other hand, what Angular provides that Durandal does not is exactly that balance of prescription and flexibility. Angular tells you how to do things like module structure and model-view-star, and as a development project lead, I appreciate that, because this makes establishing best practices and code reviews manageable. That is why I am expecting great things from Angular, especially if the next version also results in an update to the angular-ui.bootstrap project, providing a ready to use library of web components.