Tuesday, August 25, 2015

Angular Service and Factory are just the same

That is, the values of service/factory values being passed to controllers are singletons.

The only difference between the two; with service it's Angular's job to do the new'ing, with factory it's the responsibility of your factory's callback to do the new'ing. Despite the name factory, don't be confused that it gets called every time it is needed by controllers, that it can make a new instance every time it is called; in fact, the factory's callback is only called once by Angular, effectively its result is also cached just like service. Here are the screenshots showing how many times the service and factory are being called.


Service:


Factory:



As shown on screenshot, Domain.Product is new'd only once on service, even the factory is just called once. Hence the values being passed to controllers, be it from service or from factory, have just the same instance, are effectively singletons.


Imagine service is implemented as:
function service(nameHere, c) {
    cache[nameHere] = new c(); // new'd once only.
} 

Imagine factory is implemented as:
function factory(nameHere, c) {
    cache[nameHere] = c(); // called once only.
}


As for which one is used more often or should be used more often. If factory is called every time it is being needed on controller, it will fit the name factory more . But alas, factory is just called once, effectively returning singletons only, it's better to use service if all you need is singleton.


You can even use service if you want to make a real factory. Of course, you can also use factory if you want to make a real factory :)


/TheApp.ts:
///<reference path="../typings/requirejs/require.d.ts"/>
///<reference path="../typings/angularjs/angular.d.ts"/>

///<reference path="../shared/Domain/Product.ts"/>



define(['angular', 'angularUIRouter', 'angularResource', 'couchPotato' ], function(angular, angularUIRouter, angularResource, couchPotato) {

    var app = angular.module('niceApp',['ui.router','ngResource','scs.couch-potato']);


    var useService : boolean = true;

    if (useService)
        app.service('domainProduct', Domain.Product);
    else
        app.factory('domainProduct', () => {
            console.log('Factory');
            return new Domain.Product();
        });

    couchPotato.configureApp(app); // this dynamically adds registerProvider on angular module niceApp

    return app;

});

/shared/Domain/Product.ts:
module Domain {

    export class Product {
    
        name : string;
        yearModel : number;

        constructor() {
            this.name = "Initial Value";
            this.yearModel = 1900;

            console.log('Product Constructor');
        }
    }
}

/app-dir/Product/Controller.ts
//<reference path="../../../typings/requirejs/require.d.ts"/>
///<reference path="../../../typings/angularjs/angular.d.ts"/>
///<reference path="../../../shared/Domain/Product.ts"/>


class Controller {

    sampleMessage : string;

    domainProduct : Domain.Product;

    constructor($scope : angular.IScope, domainProduct) {

        console.log("Product's Controller: User of factory/services");
        
        this.domainProduct = domainProduct;

    }
    
}

define(['theApp'], function (app) {
    app.registerController('ProductController',['$scope', 'domainProduct', Controller]);
});

/app-dir/Product/SidebarController.ts
///<reference path="../../../typings/requirejs/require.d.ts"/>
///<reference path="../../../typings/angularjs/angular.d.ts"/>
///<reference path="../../../shared/Domain/Product.ts"/>

class Controller {

    sampleMessage : string;

    domainProduct : Domain.Product;

    constructor($scope : angular.IScope, domainProduct) {
    
        console.log("Product's Sidebar Controller: User of factory/services");

        this.domainProduct = domainProduct;
    }
}


define(['theApp'], function (app) {
    app.registerController('ProductSidebarController',['$scope', 'domainProduct', Controller]);
});

No comments:

Post a Comment