One issue you may run into with the FileTransfer plugin is that it only lets you do one transfer at a time. You can get around this by using XHR2 (for uploads anyway), but I thought it would be nice to demonstrate how to work with multiple transfers using promises. The FileTransfer plugin does not use promises by default, but luckily you can simply use ngCordova and use the promisified (that's a word) version of the plugin.

For this demo I'm using Ionic and ngCordova, although in theory you can use ngCordova without Ionic. I created a new application with the blank template. I then used bowser to install ngCordova, which wasn't actually necessary since the CLI supports adding it:

I then whipped up the following demo. I don't like putting everything in one JS file for my Angular projects, but since this is just a demo, I guess that's ok.

angular.module('starter', ['ionic','ngCordova'])
.config(['$compileProvider', function($compileProvider) {


.controller('Main', ["$ionicPlatform", "$cordovaFileTransfer", "$q", "$scope",
    function($ionicPlatform, $cordovaFileTransfer, $q, $scope) {
    console.log("running Main controller");
    $scope.images = [];

    $ionicPlatform.ready(function() {
      //resources to download
      var resources = [

      var promises = [];

      resources.forEach(function(i,x) {
        var targetPath = cordova.file.documentsDirectory + "image"+x+".jpg";
        promises.push($, targetPath, {}, true));

      $q.all(promises).then(function(res) {
        console.log("in theory, all done");
        for(var i=0; i<res.length; i++) {

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
    if(window.StatusBar) {

Ok, let's take this from the top. First off - the config block is just there to allow for File based URIs in my dom. Angular is a bit anal (ok, secure) about what it allows for image urls. The next bit is my controller, Main. I've got 5 URLs for different kittens at I create an array to store my promises, and then just loop over the URLs. For each one I call the ngCordova-wrapped file transfer download method. Since it returns a promise I end up with an array of promises.

Finally, I use Angular's all method for their $q library to simply say, "Do this when they are all done." I then push the final URLs into an array that is used in my view. Here's the index.html:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="css/" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <script src="lib/ngCordova/dist/ng-cordova.js"></script>
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
  <body ng-app="starter">

      <ion-header-bar class="bar-stable">
        <h1 class="title">Ionic Blank Starter</h1>
      <ion-content ng-controller="Main">
        <div ng-repeat="img in images">
          <img ng-src="{{img}}">

And that's it. The result is a set of cat pictures, which, to be honest, is what all apps should end up with:

iOS Simulator Screen Shot Apr 13, 2015, 11.24.03 AM

Similar code would work for uploads as well. Again, you do not need to use Ionic/ngCordova for this. You could create your own promises and do this by hand with a bit more work. (I've got a vide on deferreds and jQuery that may make this easier for you.)