2

I am trying to retrieve json data through an angular factory function and feeding the data to a controller to create a chart (highchart) object. However, this gives me a "Argument 'Factory Function Name' is not a function, got undefined" error. My javascript contains an angular module containing a controller and factory (as mentioned) along with a directive which renders the chart.

My javascript is:

var app = angular.module('charts', []);

app.directive('highchart', function () {
    return {
        restrict: 'E',
        template: '<div></div>',
        replace: true,
        link: function (scope, element, attrs) {
            scope.$watch(function () {
                return attrs.chart;
            }, function () {
                if (!attrs.chart) return;
                var charts = JSON.parse(attrs.chart);
                $(element[0]).highcharts(charts);
            });
        }
    };
});

app.factory('GetOverSpeedWorstData', function ($scope, $http) {
    $http.get('http://localhost:5155/overspeedworst/OverSpeedworst').success(function (data, status) {
        $scope.score = [];
        for (var i = 0; i < data.length; i++) {
            score.push(data[i].Score);
        }
        $scope.name = [];
        for (var i = 0; i < data.length; i++) {
            name.push(data[i].Name);
        }
    }).error("error message");
    $timeout($scope.fetch, 1000);
});

app.controller('Ctrl', function ($scope, GetOverSpeedWorstData) {
    $scope.name = GetOverSpeedWorstData.name;
    $scope.score = GetOverSpeedWorstData.score;
    $scope.renderChart = {
        chart: {
            type: 'bar'
        },
        xAxis: {
            categories: name
        },
        series: [{
            data: score
        }],
        legend: {
            enabled: false
        }
    };
});

and my HTML is:

<!DOCTYPE>
<html xmlns="http://www.w3.org/1999/xhtml">        
    <head>
        <title>Dashboard Application</title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
        <script src="http://code.highcharts.com/highcharts.js"></script>
        <script type="text/javascript" src="Scripts/OverSpeedWorstDataServiceApp.js"></script>
        <script type="text/javascript" src="Scripts/DashboardCtrl.js"></script>
        <link rel="stylesheet" type="text/css" href="Dashboard.css">
    </head>
    <body>
        <table>
            <tr>
                <td>
                    <h2>Overspeed (Worst) Scores</h2>
                    <section ng-app="OverSpeedWorstDataServiceApp">
                        <div ng-controller="GetOverSpeedWorstData">
                            <highchart chart='{{renderChart}}'></highchart>
                        </div>
                    </section>
                </td>
                <td>
                     <h2>Overspeed (Best) Scores</h2>
                </td>
            </tr>
            <tr>
                <td>
                     <h2>Vehicle Mileage</h2>
                </td>
                <td>
                     <h2>Servicing Report</h2>
                </td>
            </tr>
        </table>
    </body>
</html>

Any advice on why is this happening? Moreover, this runs perfectly if I retrieve the data within the controller (the related code is pasted as well).

var app = angular.module('charts', []);

app.directive('highchart', function () {
    return {
        restrict: 'E',
        template: '<div></div>',
        replace: true,
        link: function (scope, element, attrs) {
            scope.$watch(function () {
                return attrs.chart;
            }, function () {
                if (!attrs.chart) return;
                var charts = JSON.parse(attrs.chart);
                $(element[0]).highcharts(charts);
            });
        }
    };
});

app.controller('Ctrl', function ($scope, $http, $timeout) {
    $http.get('http://localhost:5155/overspeedworst/OverSpeedworst').success(function (data, status) {
        var score = [];
        for (var i = 0; i < data.length; i++) {
            score.push(data[i].Score);
        }
        var name = [];
        for (var i = 0; i < data.length; i++) {
            name.push(data[i].Name);
        }
        $scope.renderChart = {
            chart: {
                type: 'bar'
            },
            xAxis: {
                categories: name
            },
            series: [{
                data: score
            }],
            legend: {
                enabled: false
            }
        };
    }).error("error message");
    $timeout($scope.fetch, 1000);
});

To add more, my json data is of the form:

[{
    "Name": "A",
    "Score": 900
}, {
    "Name": "B",
    "Score": 846
}, {
    "Name": "C",
    "Score": 757
}, {
    "Name": "D",
    "Score": 321
}, {
    "Name": "E",
    "Score": 222
}]
Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
user2547150
  • 171
  • 1
  • 1
  • 8

2 Answers2

2

Your problem is not the controller but the way you define the service, with a factory: Angularjs - Declaring factory with a single object with a nested array - getting ReferenceError: .... is not defined

You should probably be doing something like:

app.factory('GetOverSpeedWorstData', function ($scope,$http) {
    var r;
    $http.get('http://localhost:5155/overspeedworst/OverSpeedworst').success(function (data, status) {
        stuff, like r = data
    }).error("error message");
     error stuff    
    });

    return {service methods here};

otherwise your factory is not factoring anything. it has to return something.

Community
  • 1
  • 1
Eduard Gamonal
  • 8,023
  • 5
  • 41
  • 46
  • Hi Eduard, Thanks for your prompt reply. I have been trying with your suggestion for quite a while now but still didn't manage to resolve the issue. If I get the data and do the manipulation within the controller it works but if I get the data through a factory and do the manipulation in the controller, it doesn't. Could you please revisit the problem and advice . Please find the Plunker links for the two approaches, http://plnkr.co/edit/6fzjT8zoeR3zgSnIKVK9?p=preview (works fine) http://plnkr.co/edit/EaWAEH8oi3BwbKTrEuxO?p=preview (doesn't work) – user2547150 Jul 17 '13 at 14:17
  • 1
    you have plenty of errors there. Didn't you check firebug's console? I updated it http://plnkr.co/edit/UbLqiO2kTJvb59ZikaKO?p=preview You will need to use promises to make sure that data is resolved when you look it up in the controller. read this http://stackoverflow.com/questions/16286605/initialize-angularjs-service-with-asynchronous-data – Eduard Gamonal Jul 17 '13 at 14:25
  • @EduardGamonal will you explain a bit more... now am stuck too in this same problem..... – Bijay Rai Dec 11 '14 at 11:09
0

1) Define a service:

app.factory('GetOverSpeedWorstData',
    function ($resource) {
        var apiPath = 'http://localhost:5155/overspeedworst/OverSpeedworst';
        return $resource(apiPath, {}, {
           'query':  {method:'GET', isArray:true}               
        });
});

2) In a controller do this

app.controller('Ctrl', function ($scope, $http, $timeout, GetOverSpeedWorstData) {

     $scope.list = new GetOverSpeedWorstData();

     $scope.list.$query(success, error); // or use promise

     function success (data) {
        //data manipulation
     };

     function error (data) {
       //error handling
     }; 
});

3) Dance like nobody is watching you!

Stanislav Ostapenko
  • 1,122
  • 8
  • 14