Search code examples
jsonangularjscsvpapaparse

Angular factory does not return array of objects but a single object


I am new to angular and I am trying to load a CSV list inside a factory and then convert it to json. I am using Papaparse (CSV to json library) inside the factory. When I console log the factory I get the array of objects which is exactly what I want but when I pass it inside my controller I get a single object which holds all the data.

This is my factory

(function() {

  var app = angular.module('test');

  app.factory('testFactory', ['$http', function($http) {

    var url = 'my-list.csv';

    var getContact = function() {

        return $http.get(url).success(function(data) {
            Papa.parse(data, {
                header: true,
                complete: function(results) {
                    console.log(results.data);
                    return results.data;
                }
            });
        });
      };

      return {
        getContact: getContact
      };
  }]);
}());

And this is my controller

(function() {

  var app = angular.module('test');

  app.controller('testCtrl', ['$scope', 'testFactory', function($scope, testFactory) {

    testFactory.getContact().then(function(data) {
         $scope.contacts = data;
         console.log(data);
     });
     
  }]);

}());

I want be able to do something like this inside my view

{{ contact.firstname }}

Solution

  • The issue is the order of resolution. Inspecting the console statements shows that you're assigning $scope.contacts to the resolution of the $http.get promise, and not the actual parsing.

    Instead of returning the $http.get promise, return a deferred promise and resolve at the end of parsing:

    var parsePromise = $q.defer();
    $http.get(url).success(function(data) {
        Papa.parse(data, {
            header: true,
            complete: function(results) {
                console.log(results.data);
                parsePromise.resolve(results.data);
            }
        });
    });
    return parsePromise.promise;
    

    See working demo here.

    Update: As per the comments, you could use .then to chain promises instead of creating a new deferred. The plunkr has both, you can use the changelog to toggle methods.