0

I'm having some difficulties with Typescript.

If I would make a factory in AngularJS with Javascript like this:

;(function () { 'use strict';

angular.module('mercuryServices')
    .factory('Ride', RideModelFactory);

RideModelFactory.$inject = [
    '$http',
    '$resource'
];

function RideModelFactory(
    $http,
    $filter,
    $resource
) {
    return {
        get : function() {
            return $http.get('/api/rides/');
        },
        save : function(
            rideData
        ) {
            //rideData.ridedate = $filter('date')(rideData.ridedate, "dd-MM-yyyy HH:mm:ss");
            console.log(rideData);
            return $http({
                method: 'POST',
                url: '/api/rides/',
                headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
                data: $.param(rideData)
            });
        },
        delete : function(
            id
        )
        {
            return $http.delete("/api/rides/" + id);
        },
        update : function(
            id,
            rideEdit
        )
        {
            return $http({
                method: 'PATCH',
                url: '/api/rides/' + id,
                headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
                data: $.param(rideEdit)
            });
        },
        show : function(
            id
        )
        {
            return $http.get('/api/rides/' + id);
        }
    }
}

})();

How would this translate to Typescript? This is what I have so far, but I get the error: "Provider 'RideModelFactory' must return a value from $get factory method."

module mercuryServices {
'use strict';

export interface IRideModelFactory
{
    Store(rideData: string[]);
}

export class RideModelFactory {

    public static $inject = [
        '$http'
    ];

    http: ng.IHttpService;

    constructor($http: angular.IHttpService) {
        this.http = $http;
    }

    Store(rideData: string[])
        {
            return{
                save: function(
                    rideData
                ){
                    console.log(rideData);
                    return this.http({
                        method: 'POST',
                        url: '/api/rides/',
                        headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
                        data: $.param(rideData)
                    });
                }
            }
        }
}

angular.module('mercuryServices')
    .factory('RideModelFactory', RideModelFactory);

}

2
  • Don't quite get the problem... and AuthService is not even mentioned in your code snippet... (just as a hint, you can write constructor(public $http: angular.IHttpService) to avoid having to assign the injection in the constructor body) Commented Mar 12, 2016 at 22:50
  • I'm sorry. I adjusted the code to ask my question (the Typescript project is another project, but the Javascript one is the outcome I'm going for. I have updated my question). I would like to have the same uses for the factory in Typescript like the one in Javascript. So actually 'convert' the Javascript factory to Typescript. Commented Mar 12, 2016 at 23:01

1 Answer 1

1

If you just want to build a "Service" that exposes some methods without any further abilities, my suggestion is to just use an angular service. When using TypeScript, that is as easy as declaring a class SampleService and registering this constructor function at the angular module like so:

class SampleService {
  constructor(...) {}
  someMethod() {}
}
angular.module("sampleapp", [])
  .service("SampleService", SampleService)

Angular then creates an instance of the Service by newing the function you passed. When using the factory method to register a factory, this is not the case. The method passed to factory must return an object when called, like so:

function SomeFactoryFunction() {
  return {
    someMethod: function() {...}
  }
}

So if you want to use a factory, you must either write a correct factory function or instantiate the given class by yourself. A disadvantage of this approach is that you have to repeat the list of your dependencies.

angular.module("sampleapp", [])
  .factory("SampleFactory", ($http) => new SampleFactory($http))

But unless you have a specific reason for a factory, just go with the service and let angular instantiate your service class.

I built a little jsbin showing the different ways how to use TypeScript with angular factories here: http://jsbin.com/walati/71/edit?html,js,output

If you are interested in more details when using a factory has advantages over a regular service, see this great post by Todd Motto here: https://toddmotto.com/factory-versus-service

My recommendation is to use classes where appropriate and not trying to fit everything into a class. You can easily write some nicely typed function, that returns an object that implements an interface you defined in your project.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for you comment, it really helped me a lot! Could it be the jsbin has a little error? When I try to call the method from the controller, it returns an error saying: "this.SampleService.loadData is not a function".
The jsbin linked in the answer works for me (it makes three calls to the different services). Where do you get this error? Please try the linked version directly again...
Typo from my side. Thank you for your help, your answer is correct!

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.