0

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);

Tried to update based on refactored code provided in example 2 below, but $scope.waveData is now returning empty array. I am providing updated (and more complete) code:

Chart.js:

var WaveChart = angular.module('WaveChart', ["highcharts-ng"]);


var waveData = {
        waimea: "assets/wave-waimea.json",
        pauwela: "assets/wave-pauwela.json",
        hanalei: "assets/wave-hanalei.json"
    }


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

    var getWaveDataFunction = function(beach){

        return $http.get(waveData[beach])
          .then(function(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);
            }

            return { time: Time, output: Output };

        });

    }

    return {
        getWaveData: getWaveDataFunction
    };
});      

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


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

    waveService.getWaveData(currentBeach)
        .then(function(waveData){

            $scope.waveData = waveData;
            console.log($scope.waveData);

             $scope.chartConfig = {
                    title: {
                        text: 'Wave Height Observations'
                    },
                    subtitle: {
                        text: 'according to the PacIOOS'
                    },
                    options: {
                        chart: {
                            type: 'spline'
                        },
                        plotOptions: {
                            spline: {
                                lineWidth: 2,
                                states: {
                                    hover: {
                                        lineWidth: 3
                                    }
                                },
                                marker: {
                                    enabled: false
                                }
                            },
                            area: {
                            fillColor: {
                                linearGradient: { x1: 0, y1: 0},
                                stops: [
                                    [0, Highcharts.getOptions().colors[0]],
                                    [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                                ]
                            },
                            marker: {
                                enabled: true
                            },
                            lineWidth: 1,
                            states: {
                                hover: {
                                    lineWidth: 2
                                }
                            },
                            threshold: null
                            }
                        }
                    },
                    xAxis: {
                    name: "Time", 
                    categories: waveData.time  

                },
                    yAxis: {
                        title: {
                            text: 'Wave Height'
                        },
                        labels: {
                            formatter: function () {
                                return this.value;
                            }
                        }
                    },
                    tooltip: {
                        crosshairs: true,
                        shared: true
                    },
                    plotOptions: {
                        spline: {
                            marker: {
                                radius: 4,
                                lineColor: '#666666',
                                lineWidth: 1
                            }
                        }
                    },
                    series: [{
                        name: 'Wave Height',
                        marker: {
                            symbol: 'square'
                        },
                        data: waveData.output

                    }]
                }

        });

});

wave-waimea.json

[
    {"Time":"00:09", "Output":4.40},
    {"Time":"00:39", "Output":4.63},
    {"Time":"01:09", "Output":4.72},
    {"Time":"01:39", "Output":4.69},
    {"Time":"02:09", "Output":4.20},
    {"Time":"02:39", "Output":4.92},
    {"Time":"03:09", "Output":4.89},
    {"Time":"03:39", "Output":4.89},
    {"Time":"04:09", "Output":5.18},
    {"Time":"04:39", "Output":5.18},
    {"Time":"05:09", "Output":5.41},
    {"Time":"05:39", "Output":5.71},
    {"Time":"06:09", "Output":5.91},
    {"Time":"06:39", "Output":5.68},
    {"Time":"07:09", "Output":6.33},
    {"Time":"07:39", "Output":6.53},
    {"Time":"08:09", "Output":6.23},
    {"Time":"08:39", "Output":6.63},
    {"Time":"09:09", "Output":7.58},
    {"Time":"09:39", "Output":6.43},
    {"Time":"10:09", "Output":6.86},
    {"Time":"10:39", "Output":6.89},
    {"Time":"11:09", "Output":7.25},
    {"Time":"11:39", "Output":7.35},
    {"Time":"12:09", "Output":7.12},
    {"Time":"12:39", "Output":7.15},
    {"Time":"13:09", "Output":6.73},
    {"Time":"13:39", "Output":6.89},
    {"Time":"14:09", "Output":6.63},
    {"Time":"14:39", "Output":7.48}


]
marmac
  • 1
  • 3
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Phil Nov 02 '16 at 03:20
  • @Phil - it is related, I would refer OP further to the "Use promises" section of the (very in-depth) accepted answer there. – plong0 Nov 02 '16 at 03:53
  • Possible duplicate of [Processing $http response in service](http://stackoverflow.com/questions/12505760/processing-http-response-in-service) – georgeawg Nov 02 '16 at 16:20

1 Answers1

1

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) {

    var getWaveDataFunction = function(beach){
        // return then $http.get promise
        return $http.get(waveData[beach])
          .then(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);

            // return value here is what the $http.get promise will resolve
            return { time: Time, output: Output };
        });
    }

    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);
}
plong0
  • 2,140
  • 1
  • 19
  • 18
  • I really appreciate the example, this helped a lot. I had been reading about promises and looking at code samples but was finding it difficult to relate to what I was working on, so this was incredibly helpful. – marmac Nov 02 '16 at 11:36
  • 1
    Example #2 is a classic [deferred anti-pattern](http://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). There is no need to manufacture a promise with `$q.defer` as the `$http` service already returns s promise. The promise returned will hang if the `$http` returns an error. – georgeawg Nov 02 '16 at 15:31
  • 1
    In addition the `.success` and `.error` methods are deprecated and have been [removed from AngularJS 1.6](https://github.com/angular/angular.js/pull/15157). – georgeawg Nov 02 '16 at 16:12
  • @georgeawg thanks, you are right about the anti-pattern. I've updated my answer to be more proper. I wanted the example to be easy to understand so OP could understand more about promises. Cheers – plong0 Nov 02 '16 at 18:27
  • The problem with echoing an OPs bad style is that other readers seeking answers will copy the answer and its bad style. Now example 2 has two problems. The `.then` method invokes the handler function with a response object; not data. Data is a property of the response object, i.e. `response.data`. And `$http.get(waveData[beach])` doesn't make sense. – georgeawg Nov 02 '16 at 20:45
  • @georgeawg I'm not sure how $http.get(waveData[beach]) doesn't make sense. It does work exactly as intended, and selects the correct waveData file based on the information passed as (beach). If you know a better way of doing this please share. It doesn't help anyone when you criticize without offering helpful advice or examples. – marmac Nov 03 '16 at 21:47
  • @marmac, I think it's just that you didn't include the bit of code that defined `waveData` ;) – plong0 Nov 03 '16 at 22:11
  • @plong0 I tried the refactored code but it's not working for me? $scope.waveData is returning an empty array in the controller now. I will post an update above. – marmac Nov 05 '16 at 17:40