Thomas.Benz
Thomas.Benz

Reputation: 8599

Inject service to controller

I am new to Angular. I have a simple web page, but the codes for controller are not working. It seems I do not call or inject service "ListLogsFactory" in the controller properly. Please help. Thank you.

My codes include a module, service, and controller that all declared/defined as follows:

    var myApp = angular.module("ListLogsModule", []);


    myApp.factory('ListLogsFactory', function ($http) {
            var thisPageNumber = 1;
            var thisPageSize = 10;
            var baseUrl = '../Api/LogApi/GetLogsByPage';

            var items = {};

            $http({
                method: 'GET',
                url: baseUrl,
                data: $.param({ pageNumber: thisPageNumber, pageSize: thisPageSize })
            })
            .success(function (data, status, headers, config) {
                items = data;
                console.log(items);
            })
            .error(function (data, status, headers, config) {
                alert('error: ' + status);
            });

            function getData() {
                return items;
            }
    });

    // The error is seen in FireFox and happens in the controller code:
    myApp.controllers.ListLogsController = function ($scope, ListLogsFactory) {
       $scope.logs = ListLogsFactory.getData(); // NOTE: this line throws error on running with something like "ListLogsFactory" is undefined
   }

Upvotes: 1

Views: 204

Answers (3)

Thomas.Benz
Thomas.Benz

Reputation: 8599

The following is extended the suggestions from @Eduard Gamonal to make variables/methods of angular service or factory, so it is considered a trick to remember syntax of angular service or factory.

Trick to memorize syntax of "service" or "factory" in Angular

Service is tied with "service" key word; "this" key word to make function instance members public; and "=" to make assignments to "function instance members".

Factory is tied with "factory" key word; "return" keyword to make/return a public object; and ":" to all key/value pairs assignments.

Details.

Service deals with "variables" (or "instance members"), and to make them "public", I use the "this" keyword, and because a service deals with "variables" (or "instance members") to-be-public we use "=" after a "variable" name.

"getLogs" can be treated like a "public variable" or "instance member", and written (in "assignment" meaning) like this.getLogs = function() {...}.

And the whole service is defined with the "service" key word:

<script type="text/javascript">
    var myApp = angular.module("ListLogsModule", []);

    myApp.service('ListLogsService', function () {


            this.getLogs = function () {
                var logs = [
                            {"LogId":5405,"RecordedDate" : "2012-11-19T14:22:02.247", "Event" : "Log On"},
                             {"LogId":5416,"RecordedDate" : "2012-11-19T14:55:02.247", "Event" : "Log Out"}
                ];
                return logs;
            }
    });


    myApp.controller('ListLogsCtrl', function ($scope, ListLogsService) {
        $scope.logs = ListLogsService.getLogs();               
    });  

</script>

Factory deals with a returned "object" and to make them "public", I use the "return" keyword, and because a factory deals with "object" to-look-like-JSON-object I use ":" after each "property" name inside { } of the "return" statement.

"getLogs" can be treated like a property (or key) of the returned JSON object, and is written (in "key/value" pair) like getLogs : function() {...}.

And the whole factory is defined with the "factory" key word:

<script type="text/javascript">
    var myApp = angular.module("ListLogsModule", []);

    myApp.factory('ListLogsFactory', function () {


            return {
                getLogs: function () {
                    return[
                                {"LogId":5405,"RecordedDate" : "2012-11-19T14:22:02.247", "Event" : "Log On"},
                                 {"LogId":5416,"RecordedDate" : "2012-11-19T14:55:02.247", "Event" : "Log Out"}
                    ];
                }
            }
    });


    myApp.controller('ListLogsCtrl', function ($scope, ListLogsFactory) {
        $scope.logs = ListLogsFactory.getLogs();
    });  

</script>

In summary: To memorize syntax of "service" or "factory" in Angular

Service is tied with "service" key word; "this" key word to make function instance members public; and "=" to make assignments to "function instance members".

Factory is tied with "factory" key word; "return" keyword to make/return a public object; and ":" to all key/value pairs assignments.

Upvotes: 1

Eduard Gamonal
Eduard Gamonal

Reputation: 8031

When you use factory you have to return something. You're just defining a bunch of methods there but they aren't available to anybody.

It's also good to use a different naming convention. For example, instead of LogsController, use LogsCtrl. AngularJS appends "Controller" internally and you might end up, in exotic situations, handling names like "LogsControllerController".

A simplified approach of using factory and returning the service:

var ListLogsModule = angular.module("myApp", []);

ListLogsModule.factory('ListLogsSrv', function ($http) {
    // first define the service (you're using a factory)
    var getData = function() {
        return "hey";//items;
    };

    // then return it.
    // offer a public method "getData" that uses your internal getData()
    return {
        getData : getData
    }
});

ListLogsModule.controller("ListLogsCtrl", function ($scope, ListLogsSrv) {
    $scope.w = "world";
    $scope.logs = ListLogsSrv.getData(); 
});

You also have an $http request in the factory. That means that you'll trigger the async request when you instantiate the service (when it is used for the first time), so nobody will wait for it to finish and you'll be getting undefined. If you are using this service in a controller, you will probably need to resolve a promise.

An example of using a promise:

var promise = $q.defer();
var thisPageNumber = 1;
...
var baseUrl = '../Api/LogApi/GetLogsByPage';
...
promise = $http.get(...

Now you can use this promise in the controller, for example, or in the methods of your service.

I answered a related question two days ago Angular Service Definition: service or factory

Upvotes: 3

dnc253
dnc253

Reputation: 40337

myApp.controllers.ListLogsController = function ($scope, ListLogsFactory) {
       $scope.logs = ListLogsFactory.getData();
}

should be

myApp.controller("ListLogsController", function ($scope, ListLogsFactory) {
       $scope.logs = ListLogsFactory.getData();
});

Upvotes: 1

Related Questions