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}


]
3

1 Answer 1

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);
}
Sign up to request clarification or add additional context in comments.

8 Comments

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.
Example #2 is a classic deferred anti-pattern. 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.
In addition the .success and .error methods are deprecated and have been removed from AngularJS 1.6.
@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
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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.