DannyBoy
DannyBoy

Reputation: 444

How to sort the loaded XML data

In my application, I have an XML file that connects to different API and gathers information. Then in a div, it shows the fetched information. I do it successfully, but the issue is, the XML will not load if element one by one. It loads data in parallel, so the divs it creates are not in the right order like how they are in the xml file.

Here is a demo that get some data from local, SoundCloud, Spotify and iTunes.

And this is the XML file it is loading from:

$.ajax({
  url: "https://dl.dropboxusercontent.com/u/33538012/text.xml",
  dataType: "xml",
  success: parse,
  error: function() {
    alert("Error");
  }
});

function parse(document) {
  var inc = 1;

  $(document).find("track").each(function() {
    var rowNum = inc;
    var trackType = $(this).find('type').text();
    var trackTitle = $(this).find('title').text();
    var soundcloud_url = $(this).find('soundcloud_url').text();
    var spotify_track_uri = $(this).find('spotify_track_uri').text();
    var itunes_id = $(this).find('itunes_id').text();
    
    if (trackType == "audio") {
      inc = inc + 1;
      $(".playlist").append("<div id='" + rowNum + "' >" + rowNum + " " + trackTitle + "</div>");
      
    } else if (trackType == "soundcloud") {
      inc = inc + 1;
      SC.initialize({
        client_id: "b8f06bbb8e4e9e201f9e6e46001c3acb"
      });
      SC.resolve(soundcloud_url).then(function(sound) {
        trackTitle = sound.title;
        $(".playlist").append("<div id='" + rowNum + "' >" + rowNum + " " + trackTitle + "</div>");
      });
      
    } else if (trackType == "spotify") {
      inc = inc + 1;
      var spotifyLink = "https://api.spotify.com/v1/tracks/" + spotify_track_uri;
      $.getJSON(spotifyLink, function(data) {
        trackTitle = data.name;
        $(".playlist").append("<div id='" + rowNum + "' >" + rowNum + " " + trackTitle + "</div>");
      });
      
    } else if (trackType == "itunes") {
      inc = inc + 1;
      var iTuensLink = "https://itunes.apple.com/lookup?id=" + itunes_id + "&callback=?";
      $.getJSON(iTuensLink, function(data) {
        trackTitle = data.results[0].trackName;
        $(".playlist").append("<div id='" + rowNum + "' >" + rowNum + " " + trackTitle + "</div>");
      })
    }
    
  });

}
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="playlist"></div>

If you look at the result of the code, the the number next to each row shows the order in the original XML file, but they are not loaded exactly one after each other.

Any way to sort the loaded files just like how they are written in the XML file?

Upvotes: 0

Views: 153

Answers (1)

Vinay
Vinay

Reputation: 7676

You can use deffered object which are an extension of promise and can resolve it self.So they can act as a trigger when used with resolve

Crate an array that would hold our deffered objects note that order is important therefore numeric array is used Just create a deffered

var dfd = jQuery.Deferred();

Define what should be done on

dfd.then(function(){
  $(".playlist").append("<div id='" + rowNum + "' >" + rowNum + " " + trackTitle + "</div>");
  })

Finally push it on our array

  x.push(dfd)

After all api calls are over just call resolve on each

$.each(x, function(){
    this.resolve(); //then callback gets called one by one on each deffered 
});

https://jsfiddle.net/sanddune/rr7tord6/

You might want to have some mechanism to detect when the slowest call finishes and then call resolve

EDIT:

The latency of individual api varies greatly across geographies for example for me soundcloud was the most "laggy" so it ended up last but for someone else itunes may be the last to finish this is due to many variables like distance from server,ISP,throttling etc. so clearly you can never rely on "last man standing " approach so i could only suggest that use some sort of counter like this to track how many request are outstanding

First get total no. of nodes (inn xml) that have an api involved say you have just soundcloud and shopify so now total = 2 ; count = 0

so when the api request yields increment it by one like

$.getJSON(spotifyLink, function(data) {
    trackTitle = data.name;
    alert('shopify loaded'); 
    count++;check();
});

or

SC.resolve(soundcloud_url).then(function(sound) {
    trackTitle = sound.title;
    alert('soundcloud loaded'); 
    count++;check();
});

note that you need to increment on even failed api request (which may result from bad parameter etc.)

call a check function that will check if count == total on every success/fail part of api request

function check(){
  if(count==total)
  alert('all api request finished');
  //resolve all deffereds
}

Upvotes: 1

Related Questions