Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS service inheritance

I have next service:

angular.module('app').service('BaseService', function (alertService) {
   var service = {};
   service.message =  "Hello";
   service.perform = function () {
        alertService.add("success",service.message);
   };
   return service;
});

Now I want to inherit this service in some 'ChildService' with overriding message on "World!". I expect that calling ChildService.perform() will show alert with "World!".

What is proper way to do this?

like image 295
Alexey Avatar asked Oct 29 '14 23:10

Alexey


3 Answers

AngularJS does not provide any mechanism to implement inheritance of services directly, however for your case you can use $provide.decorator to extend BaseService itself or use it like a prototype of another ChildService using plain JavaScript. In my practice, in order to have service with configurable state and behaviour I use providers. In all of the following examples the console output will be World.

Decorator

If you don't need the original BaseService in your module, you can decorate it

Plunker

function AlertService() {
  this.add = function(level, message) {
    switch(level) {
      case 'success':
        console.log(message);
    }
  }
}

function BaseService(alertService) {
  this.message =  "Hello";
  this.perform = function () {
    alertService.add("success",this.message);
  };
}

angular.
  module('app',[]).
  config(['$provide', function($provide) {
    $provide.decorator('BaseService', function($delegate) {
      $delegate.message = 'World';
      return $delegate;
    });
  }]).
  service('alertService', AlertService).
  service('BaseService', ['alertService',BaseService]).
  controller('ctrl', ['BaseService', function(baseService) {
    baseService.perform();
  }]);

Prototypical Inheritance

Plunker

function AlertService() {
  this.add = function(level, message) {
    switch(level) {
      case 'success':
        console.log(message);
    }
  }
}

function BaseService(alertService) {
  this.message =  "Hello";
  this.perform = function () {
    alertService.add("success",this.message);
  };
}

function ChildService(BaseService) {
  angular.extend(ChildService.prototype, BaseService);
  this.message = "World";
}

angular.
  module('app',[]).
  service('alertService', AlertService).
  service('BaseService', ['alertService',BaseService]).
  service('ChildService', ['BaseService',ChildService]).
  controller('ctrl', ['ChildService', function(ChildService) {
    ChildService.perform();
  }]); 

Provider

Plunker

function AlertService() {
  this.add = function(level, message) {
    switch(level) {
      case 'success':
        console.log(message);
    }
  }
}

function BaseService() {
  var message =  "Hello";

  this.setMessage = function(msg) {
    message = msg;
  }

  function Service(alertService) {
    this.perform = function () {
      alertService.add("success", message);
    };
  }

  function Factory(alertService) {
    return new Service(alertService);
  }

  this.$get = ['AlertService', Factory];
}

angular.
  module('app',[]).
  provider('BaseService', BaseService).
  config(['BaseServiceProvider', function(baseServiceProvider) {
    baseServiceProvider.setMessage('World');
  }]).
  service('AlertService', AlertService).
  controller('ctrl', ['BaseService', function(baseService) {
    baseService.perform();
  }]);
like image 97
Vadim Avatar answered Nov 17 '22 11:11

Vadim


I would modify a little bit your code:

app.factory('BaseService', function () {
   //var service = {}; 
   function service(){
       this.message = "hello";
   }; 
   service.prototype.perform = function () {
        console.log('perfom', this.message);
   };
   return new service();
});

(I just change your alertService for an console.log();.. )

then implement inheritance like this:

app.factory('childBaseService',['BaseService', function(BaseService){
    var childBaseService = function(){
            BaseService.constructor.call(this)
            this.message = 'world!';
    };

    childBaseService.prototype = Object.create(BaseService.constructor.prototype);
    childBaseService.prototype.constructor = childBaseService;

    return new childBaseService();

}]);

You could see a example of how this works.. at the end, BaseService and childService would be instances of BaseService constructor ( service ).

console.log(BaseService instanceof BaseService.constructor); //true
console.log(childBaseService instanceof BaseService.constructor); //true
like image 15
rahpuser Avatar answered Nov 17 '22 11:11

rahpuser


Here is an example, based on Constructor/new inheritance(which I would generally recommend against).

BaseService.$inject = ['alertService']
function BaseService(alertService) {
    this.message = 'hello'
    this.alertService = alertService
}

BaseService.prototype.perform = function perform() {
    this.alertService.add("success",this.message);
}


ChildService.$inject = ['alertService']
function ChildService(alertService) {
    this.message = 'hello world'
    this.alertService = alertService
}

ChildService.prototype = Object.create(BaseService.prototype)

And then you would just include these as services:

angular.module('app')
    .service('BaseService', BaseService)
    .service('ChildService', ChildService)
like image 5
Sacho Avatar answered Nov 17 '22 12:11

Sacho