AngularJS dependency injection swap implementation
Asked Answered
A

3

7

I'm still learning AngularJS, and have a question regarding their flavor of dependency injection. For example purposes, say I have a DataProcessor service which has a processData method that takes in a uri parameter and it needs to read that data (which may be xml, json, etc.) and then perform some actions on it. The DataProcessor constructor takes in an implementation of a DataReader interface that knows how to read a certain file type. Here are some example services of what I'm talking about:

// implementations of the DataReader interface
myApp.service('XmlDataReader', function() {
    this.readData = function(uri) {
        // read xml data from uri
    }
}]);

myApp.service('JsonDataReader', function() {
    this.readData = function(uri) {
        // read json data from uri
    }
}]);

// data processing service that takes in an implementation of a DataReader
myApp.service('DataProcessor', ['DataReader', function(DataReader) {

    this.processData = function(uri) {
        var readData = DataReader.readData(uri);

        // process data and return it
    }
}]);

From a typical dependency injection perspective, a specific type of DataReader could be passed into the DataProcessor and used like so:

var dataProcessor = new DataProcessor(new JsonDataReader());
var processedData = dataProcessor.processData('dataz.json');

What is the AngularJS way of doing this?

Available answered 19/12, 2013 at 14:34 Comment(0)
C
2

Do something like this:

myApp.service('DataProcessor', ['$injector', 'valueRecipeOfTheServicename', function($injector, valueRecipeOfTheServicename) {

    this.processData = function(uri) {
        var service = $injector.get(valueRecipeOfTheServicename);

        // process data and return it
    }
}]);

$injetcor.get() retrieves a service

Cladoceran answered 19/8, 2014 at 12:11 Comment(0)
I
1

Based on Noypi Gilas answer, I am initiating the controller with the name of the service and retrieving it via $injetcor.get():

myApp.service('DataProcessor', ['$injector', function($injector) {
    var service;

    $scope.init = function (serviceName) {
        service = $injector.get(serviceName);
    }

    this.processData = function(uri) {
        // use the service ...
    }
}]);
Indicator answered 24/7, 2015 at 12:9 Comment(0)
F
0

Because of the way DI works - you shouldn't have to create instances of your services, ever really. What you do is you inject the service(s) you need into your controller and it should just work. In the case above, your controller might be defined to be:

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

function MyController($scope, DataProcessor) {
    var uri = '';
    DataProcessor.processData(uri);
}

The only other thing you need to do here is make sure that "App" is the name you specify in the "ng-app" directive and make sure that your page includes the JS files with "DataProcessor" before you include the angular app module (technically these could even be defined in the same file). Hope this helps!

Edit

By the way, if you need to minify - the following is how you would define the controller:

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

// if you need to minify:
var MyController = ['$scope', 'DataProcessor',
    function($scope, DataProcessor) {
        var uri = '';
        DataProcessor.processData(uri);
    }
];

Additional Suggestions

My understanding of a service at the present time is that is is used to shared data or code between controllers. If this data processing is specific to that controller you might consider just moving the "ProcessData" implementation directly into your controller. Sometimes changes like this can be simpler than processing the data in a service. If you do process the data in the service you might still want to write that data back to the scope. In this case, you can pass $scope as a parameter into the service routine. Since I don't know too much about your use case, just take these suggestions with a grain of salt. Good luck!

Fatback answered 19/12, 2013 at 14:39 Comment(2)
But if the DataProcessor needs a specific implementation of a DataReader (e.g. JsonDataReader), how do you do that? A major benefit of dependency injection is the ability to swap implementations. All the examples I've found in AngularJS have their "dependencies" injected, but they're always just pointing to a single, specific concrete implementation of something.Available
I agree with what you are saying. One way I can think of swapping the implementation would be to have two JS files that defined the same service and use the include (script include, that is) to decide which will be used by the controller. Overall, I don't think JavaScript supports classical inheritance which makes some of the DI concepts more difficult.Fatback

© 2022 - 2024 — McMap. All rights reserved.