marmac marmac - 1 month ago 14
AngularJS Question

Angularjs - cannot pass data from factory to controller

I'm new to angular and find myself stuck. I am trying to pass data from a factory to a controller and it returns undefined no matter what I have tried. Can anyone help? Ultimately I will need to access the Time and Output variables in the controller to pass into a chart.

Code:

WaveChart.factory('waveService', function($http) {

var getWaveDataFunction = function(beach){

$http.get(waveData[beach])
.success(function(data) {
console.log('yay it works');
return data;

var Time = [];
for (var i = 0; i < data.length; i++) {
Time.push(data[i].Time);
}

var Output = [];
for (var i = 0; i < data.length; i++) {
Output.push(data[i].Output);
}
//console.log(Time);
//console.log(Output);

});
}

return {
getWaveData: getWaveDataFunction
};

});

WaveChart.controller('chartCtrl', function ($scope, waveService, $state) {


var currentBeach = $state.current.title.toLowerCase();

$scope.waveData = waveService.getWaveData(currentBeach);

console.log($scope.waveData);

Answer

This is a textbook use case of promises. Please see angular docs for details of working with promises in angularjs.

In this case, you have two options and I would recommend the second one as you do have a bit of post-processing after the http response comes through. (I've included the first one mainly to illustrate the most basic way to get an asynchronous $http response back to a controller)

1 - Return the $http promise itself and handle the response in the controller:

WaveChart.factory('waveService', function($http) {
    var getWaveDataFunction = function(beach){
        return $http.get(waveData[beach]);
    };

    return {
        getWaveData: getWaveDataFunction
    };
});


WaveChart.controller('chartCtrl', function ($scope, waveService, $state) {
    waveService.getWaveData(currentBeach)
        .success(function(data) {
            console.log('yay it works');

            var Time = [];
            for (var i = 0; i < data.length; i++) {
                Time.push(data[i].Time);   
            }

            var Output = [];
            for (var i = 0; i < data.length; i++) {
                Output.push(data[i].Output);
            }
            //console.log(Time);
            //console.log(Output);

            $scope.waveData = {
                time: Time,
                output: Output
            };
        });
});

2 - create a new promise and resolve it from the $http.success callback

WaveChart.factory('waveService', function($http, $q) {

    var getWaveDataFunction = function(beach){
        // create a new deferral
        var defer = $q.defer();

        $http.get(waveData[beach])
          .success(function(data) {
            console.log('yay it works');

            var Time = [];
            for (var i = 0; i < data.length; i++) {
                Time.push(data[i].Time);   
            }

            var Output = [];
            for (var i = 0; i < data.length; i++) {
                Output.push(data[i].Output);
            }
            //console.log(Time);
            //console.log(Output);

            // resolve promise with asynchronously-retrieved data
            defer.resolve({ time: Time, output: Output });

        });
        // you will likely want to add an error callback that does defer.reject so the caller will know the asynchronous function is complete one way or another

        // return the promise
        return defer.promise;
    }

    return {
        getWaveData: getWaveDataFunction
    };
});      

WaveChart.controller('chartCtrl', function ($scope, waveService, $state) {


    var currentBeach = $state.current.title.toLowerCase();

    // use .then callback to wait for the promise to be resolved
    waveService.getWaveData(currentBeach)
        .then(function(waveData){
            $scope.waveData = waveData;
            console.log($scope.waveData);
        });

EDIT: Just noticed you can optimize your result processing by combining the two loops over data into one:

var Time = [];
var Output = [];
for (var i = 0; i < data.length; i++) {
    Time.push(data[i].Time);
    Output.push(data[i].Output);
}