Angular and XML? No Problem!

This entry is part 7 of 9 in the series: AngularJS Learning Series

The Finished Product

JSON is a native object to AngularJS so working solely with JSON examples is easy. In the real world, however, you’ll probably need to deal with other types of data sources, like XML. Before I get too wordy, let’s start with what you’re really here for…the example:

[iframe src=”http://embed.plnkr.co/Hpx8GPHt0IqKADj8K1Qc” width=”100%” height=”365px”]

The Explanation

While the finished product looks like the result of 15 minutes of coding, I have to admit that it took me significantly longer to figure out. If you search the Angular Developer Guide or API for “XML” you’re going to come up woefully absent of useful results. Googling won’t get you much further. As frustration began to set in, I started thinking about what made loading an XML file more difficult than loading a JSON file. The answer is: not much!

Bridging the Language Gap

Angular likes JSON, and can you blame it? Angular is a JavaScript toolset and JSON is JavaScript Object Notation, a native brethren. XML, on the other hand, is tag-based markup…a foreign language to Angular. What I needed was a way to make Angular understand what XML was trying to communicate.

The key to overcoming any language gap is to have a translator. If there were a way to translate XML to JSON before handing it to the application then I could eliminate the language gap, and the problem.

A quick search for xml converters turned up multiple results. I chose Abdulla Abdurakhmano’s X2JS library because it was the first one I came across, it was lightweight, and it was pretty easy to use.

The code required to perform the translation is short and simple. Provide the library with XML, tell it which method to use, and receive JSON in return:

function(xml) {
 var x2js = new X2JS();
 var json = x2js.xml_str2json( xml );
 return json;
}

Where to Stick It

Now that I had a solution to the language gap I needed to decide where to implement it. Angular’s $http service conveniently applies transformation functions for both requests and responses. These functions apply transformations to data when it is sent and received, and they can be overridden.

Using the X2JS conversion code as a transformResponse function it was simple to get the $http service to read in XML and return JSON to the application, effectively creating the translator I needed. The results look something like this:

angular.module('myApp.service',[]).
    factory('DataSource', ['$http',function($http){
       return {
           get: function(callback){
                $http.get(
                    'data.xml',
                    {transformResponse:function(data) {
                    	// convert the data to JSON and provide
                    	// it to the success function below
						var x2js = new X2JS();
						var json = x2js.xml_str2json( data );
						return json;
						}
					}
                ).
                success(function(data, status) {
					// send the converted data back
					// to the callback function
                    callback(data);
                })
           }
       }
    }]);
    
angular.module('myApp',['myApp.service']);

var AppController = function($scope,DataSource) {
    
    //This is the callback function
    setData = function(data) {
        $scope.dataSet = data;
    }
        
    DataSource.get(setData);
    
}

That’s really all there is to it! The example above will retrieve an xml file named “data.xml”, convert it to JSON, and assign the results to $scope.dataSet.

The Caveat

XML comes in all shapes and sizes. Some use attributes, others don’t, and many use a combination of both. Some XML files use a proper header, others are just fragments. Your application will likely require tweaking to get the data into the shape that your application requires. Always read the docs, read the comments, and experiment.

The example at the beginning of this post is a great starting point. Fork it and experiment with different libraries or XML formats.

Keep on Coding!

AngularJS Data Loading and Assignment

This entry is part 4 of 9 in the series: AngularJS Learning Series

My goal with today’s AngularJS experiment is to load data from a JSON file, iterate through all the data, and dynamically display detail data from a clicked list item. This proved to be incredibly simple and ended up taking less than 50 lines of code, including comments!

The data loading is done using the AngularJS $http service. In this example, the data object is assigned to $scope.artists when it has been successfully loaded:

$http.get('artists.json').success(function(data) {
   $scope.artists = data;
});

Once the data is loaded I can iterate over it using the AngularJS ng-click directive. The code below loops over each record in the artists object that I loaded above. It displays the artistName property found in each artist and then assigned a function (setSelectedArtist) that will be executed when the name is clicked.

<ul>
	<li ng-repeat="artist in artists">
    	<a href ng-click='setSelectedArtist(artist)'>{{artist.artistName}}</a></li>
	</li>
</ul>

When an artist name is clicked, its artist object is passed to the setSelectedArtist function found in ArtistsController. setSelectedArtist assigns the artist to the scoped selectedArtist property. When that occurs, page references to selectedArtist are updated to reflect the new assignment:

<div class="detailimagewrapper">
    <img class="detailimage" src="{{selectedArtist.img}}" >
</div>
<p>{{selectedArtist.description}}</p>

Check out the example on Plunker. It’s well-commented and easy to modify. Try adding the artist’s genre to the detail section. Or add a new field, like recordLabel or dateFormed.

[iframe height=”400″ width=”100%” src=”http://embed.plnkr.co/R6u0QYAyKj3IvRGEtWp8″ ]

This post is barely the tip of the iceberg regarding what the AngularJS $http service offers. Check out the documentation to learn more.