Angular, inject factory into provider - javascript

Having a little trouble doing this, I know you need to do it with $get, however the examples I find don't quite fall into the structure I need.
My provider looks like so
.provider('moduleOb', function(){
var modules = {};
//outer closure to inject "this"
function outerAddState(moduleObj) {
};
//outer function so we can push into module
function modulePush(currentModule, name){
}
return {
goState: function(name, stateName, options) {
//I need to use this function in here which injected from a factory
checkUrl.requestUrl();
},
moduleConstructor: function(name, cb) {
},
$get: function $get() {
return this;
}
}
})
So I'm just planting the get right now at the bottom as you can see. I need to be able to inject the checkurl factory somehow so I have access to it in goState. How would I format it so I can use the get to do so?
So if I separate the factory out into a separate module I can inject it with
var injector = angular.injector(['urlParsing']);
var checkUrl = injector.get('checkUrl')
inside the provider. However, the checkurl function has a dependency on $location. So the injector cannot find $location now --
Error: [$injector:unpr] Unknown provider: $locationProvider <- $location <- checkUrl
Can I inject the location provider too? Is this the best way of doing this?
Maybe with a get ($location)? Or maybe there is a better work around. Could use some help, this has been holding me up all day! Thanks for reading.
Edit2: After a few days of wrestling with this - I realize I'm just looking how to inject multiple modules ( a factory and it's dependancies of $log and $location) to a provider. The real reason being so I can let people set what I want them to set in the .config.
I have temporarily circumvented this by changing this provider to a factory and using the .run instead of the .config BUT I would still love to be able to use .config instead.

Related

Error Unknown provider: $scopeProvider <- $scope when using $injector to inject $scope into controller

When using DI in this fashion:
var MainController = function MainController($scope) {
//use $scope here
};
MainController.$inject = ["$scope"];
It, work but, when it's used like this:
var MainController = function MainController($injector) {
var $scope = $injector.get("$scope");
};
MainController.$inject = ["$injector"];
This will result in error:
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope
Here's a plunker with an example that showcases the error, check the comments for an alternative to see that only the scope not custom services are affected by this.
I found this Angular bug where they talk about the controller being instantiated before the child $scope is being created as Tomer Avni answered, so:
why the first way of injecting $scope work while the second doesn't?
And is there a way to use the second method of Dependency injection
with $injector to inject $scope?
I've replied to you on gitter, but answering here as well as it may help other who have the same issue.
When you give Angular a function to call that has values that will be derived from dependency injection (e.g. a service, a controller, etc.), Angular will:
Look for an .$inject property on the function object which should be an array of dependency names as strings (e.g. ['$scope']).
If $inject is undefined, it will use the parameters of the function definition (which works in most cases, unless you minify your code and the names get mangled).
So, in a nutshell, it will look up the names you have specified in the DI container.
$scope doesn't exist in the DI container, only $rootScope does. So, if you're accessing the injector directly and asking for an instance of $scope, you'll get the injection error you've seen here.
In the example where it worked, you're not accessing the injector directly but instead relying on Angular working out how to create your controller. That's a subtle difference, but in this case an important one. Within Angular, when creating the controller instance it will resolve $scope to the result of calling $rootScope.$new() (i.e. what you would do when manually instantiating the controller in a unit test).
I hope that explains why your example didn't work.
As for the second question, you could manually get a scope instance by doing something like:
var $scope = $injector.get('$rootScope').$new();
But now we're starting to go down a pretty murky path... It's quite atypical to inject the $injector directly. I'd avoid that if you can. Is there a reason you need to do this?

Angular provider accepts function which needs dependencies

Wasn't sure what title to give this one but basically I have an authorization provider which I have created myself which need to be configured during the config phase to have a requireLogin() function which will be run at a later date. Like this...
// Configure $auth service
app.config(function ($authProvider, appConfig) {
$authProvider.setRequireLoginFunction(function($modal){
// Use the modal service
});
})
And this is the provider code
app.provider('$auth', function(){
var _requireLoginFn;
return({
setRequireLoginFunction: setRequireLoginFunction,
$get: instantiateAuth
});
function setRequireLoginFunction(fn){
_requireLoginFn = fn;
}
function instantiateAuth($http, $q) {
return({
requireLogin: requireLogin
});
function requireLogin() {
return _requireLoginFn.apply(undefined, arguments);
}
}
});
Sidenote: I'm using ng-annotate so don't use the array syntax of DI.
Anyway, as you can see, the function that is being stored in the config phase which will later be called using $auth.requireLogin.then(...) etc. needs access to the angular-ui modal service, but when I call the function later from inside the provider obviously the DI stuff isn't happening because all I've done is put $modal in the arguments of my function which isn't magic. I also can't put $modal in the dependencies of my provider because it's too early to do that, also my provider doesn't know what dependencies the function I pass in will need.
I feel the answer is probably to:
A) use the injector within the function I'm passing in to get access to $modal service or
B) Somehow run the function from inside the provider when called externally and somehow get all the supplied dependencies injected at runtime?
Sorry if I'm not able to explain this easily. I tried to make a JSfiddle but couldn't hack the code down easily.

Is it good practise to use angular.element("[ng-controller="someCtrl"]").scope()

Is it good practise to use angular.element("ng-controller="someCtrl"]").scope() instead of using factory to handle data flow between controllers using dependency injection. The problem here is I want to call a function of another controller, so there are two ways either I put it in a factory and reuse it among controllers or use above syntax to call the function directly.
If you need to call a function from other controller, it should be a SERVICE/Factory. This way, you will share code between controllers, and you will code with good practices.
As they say in angularjs docs
Angular services are substitutable objects that are wired together
using dependency injection (DI). You can use services to organize and
share code across your app.
Then, you just need to create a service or a factory
//The service
angular.module('myApp')
.service('serviceName', function ($http, $scope, socket) {
//This functions will be available in your controller
return {
list: function () {
$http.get(listUrl).success(function (lista) {
$scope.centerList = lista;
socket.syncUpdates('center', $scope.centerList);
});
}
};
});
//The controller
angular.module('myApp').controller('myCtrl', function ($scope, centerService) {
$scope.listCenters = function () {
centerService.list();
};
});
Just to clarify, and to add some comprehensive ideas about services and factories:
https://www.youtube.com/watch?v=J6qr6Wx3VPs
AngularJS: Service vs provider vs factory
https://www.airpair.com/angularjs/posts/top-10-mistakes-angularjs-developers-make
It is never good practice to access the DOM from a controller. So if wrapping the method in a factory/service is an option, I'd say that's the way to go.

Angular.js Call $http.get from outside controller

I have an HTTP resource that returns a JSON list of top 10 entities from a database.
I call it this way:
var filter= "john";
var myApp = angular.module('myApp', []);
myApp.controller('SearchController', ['$scope','$http', function ($scope, $http) {
$http.get('/api/Entity/Find/' + filter). //Get entities filtered
success(function (data, status, headers, config) {
$scope.entities = data;
}).
error(function () {
});
}]);
It works!
But... how can I change the filter variable in order to change the query?
Should I rewrite the whole controller to get this to work?
Update
Sorry for the lack of clarity in my question. When I asked this I couldn't undertand anything of AngularJS.
My original intent was to get the variable $http injected, without relying on creating a controller for that.
Thanks for everyone.
A likely better method
If you don't want to get it inside a controller, you could have it injected into a recipe (ex, provider, factory, service):
https://docs.angularjs.org/guide/providers
myApp.factory('getStuff', ['filter', '$http', function (filter, $http) {
//Blah
}]);
If you want to get an instance of $http outside of any angular struct, you can do what's shown below.
The method given by Dennis works; however, it does not work if called before angular has been bootstrapped. Also, it seems like Derek has an error with Dennis' method because he does not have jquery.
The solution that Exlord mentioned is better, as it does not have that problem, and is more proper:
$http = angular.injector(["ng"]).get("$http");
Explained:
The angular injector is an:
object that can be used for retrieving services as well as for dependency injection
https://docs.angularjs.org/api/ng/function/angular.injector
The function angular.injector takes the modules as a parameter and returns an instance of the injector.
So in this case you retrieve an injector for the ng module (angular's), and then retrieve the service $http.
Note:
One thing to keep in mind when using injector like this is that in my own findings it seems you need to make sure you include modules in the inject which what you are "getting" will need. For example:
angular.injector(['ng', 'ngCordova']).get('$cordovaFileTransfer')
Regarding to your question "... call $http.get from outside controller" you can do the following:
... ANYWHERE IN YOUR CODE
var $http = angular.element('html').injector().get('$http');
$http.get(...).success(...);
ANYWHERE IN YOUR CODE ...
See official docs from angular: angular $injector docs :
The get(name); method Returns an instance of the service.

Angular JS - How to safely retain global value "extracted" using a service

I need an object to be globally accessible all throughout my Angular application, and I've gladly put this object in a value service.
Unfortunately, this object is computed by another service, and I've not been able to inject myService into same value service.
ATM, I've acheived my goal with something like this:
global service code
app.service('myService', function() {
this.foo = function() {
// some code that returns an object
return computedObject
}
})
app.run(function ($rootScope, myService) {
$rootScope.global = {dbObject: myService.foo()}
})
And which I can use in any controller that pleases me by simply injecting $rootScope in it
However, I don't like the need of injecting the whole $rootScope wherever I need that damn object, and I trust is not much safe (or efficient?) either, since the team specifies
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Do you, perchance, happens to know any way I can inject a service into a service value?
Or maybe any other Angular best practice which I could exploit?
I forgot one very important notice
The computation of the object could be quite computational intense, so I absolutely don't want it to be recomputed everytime I move from page to page, or anything else really.
Ideally Using $rootScope for storing a few globally required values is totally ok. But if you are still adamant on using a module, I suggest you use a provider.
Make your 'myService' a provider and that will let you configure the variables in the service.
More info here
AngularJS: Service vs provider vs factory
You could use $broadcast to send the value from the value service to myService.
You would still need to inject $rootscope into each of the services, but from then on you could just inject myService around the rest of the app.
Reference here.
I need an object to be globally accessible all throughout my Angular application
I would use service. Since Service is singleton you can register the service to all your controllers and share any data over service.
Unfortunately, this object is computed by another service, and I've not been able to inject myService into same value service.
Just create one main service (Parent) and child service that will inherit the parent. (like abstract service in Java world).
Application.factory('AbstractObject', [function () {
var AbstractObject = Class.extend({
virtualMethod: function() {
alert("Hello world");
},
abstractMethod: function() { // You may omit abstract definitions, but they make your interface more readable
throw new Error("Pure abstract call");
}
});
return AbstractObject; // You return class definition instead of it's instance
}]);
Application.factory('DerivedObject', ['AbstractObject', function (AbstractObject) {
var DerivedObject = AbstractObject.extend({
virtualMethod: function() { // Shows two alerts: `Hey!` and `Hello world`
alert("Hey!");
this._super();
},
abstractMethod: function() {
alert("Now I'm not abstract");
}
});
return DerivedObject;
}]);
Now, we can add some logic into AbstractObject and continue use DerivedObject
Here is example Plunker

Categories

Resources