AngularJS UI Router using resolved dependency in factory / service - javascript

I have a UI Router defined something like this (trimmed for simplicity):
$stateProvider
.state('someState', {
resolve: {
model: ['modelService', 'info', function (modelService, info) {
return modelService.get(info.id).$promise;
}]
},
controller: 'SomeController'
});
This someState state is using a factory / service that is dependent on that model resolve. It's defined something like this, and AngularJS throws an Unknown provider: modelProvider <- model <- someService error here:
angular
.module('someModule')
.factory('someService', someService);
someService.$inject = ['model'];
function someService(model) { ... }
However, using the same model resolve inside of this state's controller works fine:
SomeController.$inject = ['model'];
function SomeController(model) { ... }
So I'm understanding that UI Router is delaying the DI of the SomeController until the resolve is happening, which allows AngularJS to not throw an error. However, how come the same delay is not happening when putting that resolve as a dependency on someService? Do resolves only work on controllers? And if that is the case, how can I use a resolve inside a factory / service?

Do resolves only work on controllers?
Yes, resolves only work on controllers.
And if that is the case, how can I use a resolve inside a factory / service?
Remember that factories and services return singleton objects, i.e. the first time a factory is injected into a controller, it runs any instantiation code you provide and creates an object, and then any subsequent times that factory is instantiated, that same object is returned.
In other words:
angular.module('someModule')
.factory( 'SomeFactory' , function () {
// this code only runs once
object = {}
object.now = Date.now();
return object
);
SomeFactory.now will be the current time the first time the factory is injected into a controller, but it not update on subsequent usage.
As such, the concept of resolve for a factory doesn't really make sense. If you want to have a service that does something dynamically (which is obviously very common), you need to put the logic inside functions on the singleton.
For example, in the code sample you gave, your factory depended on a model. One approach would be to inject the model into the controller using the resolve method you've already got set up, then expose a method on the singleton that accepts a model and does what you need to do, like so:
angular.module('someModule')
.factory( 'SomeFactory', function () {
return {
doSomethingWithModel: function (model) {
$http.post('wherever', model);
}
});
.controller('SomeController', function (SomeFactory, model) {
SomeFactory.doSomethingWithModel(model);
});
Alternatively, if you don't need the resolved value in the controller at all, don't put it directly in a resolve, instead put the resolve logic into a method on the service's singleton and call that method inside the resolve, passing the result to the controller.
It's hard to be more detailed with abstract conversation, so if you need further pointers then provide a specific use-case.

You cannot use the resolved values in services or factories, only in the controller that belongs to the same state as the resolved values. Services and factories are singletons and controllers are newly instantiated for (in this case) a state or anywhere else where ng-controller is used.
The instantiation happens with the $controller service that is capable of injecting objects that belong only to that controller. Services and factories do not have this capability.

You should review the angular docs on dependency injection:
Components such as services, directives, filters, and animations are defined by an injectable factory method or constructor function. These components can be injected with "service" and "value" components as dependencies.
Controllers are defined by a constructor function, which can be injected with any of the "service" and "value" components as dependencies, but they can also be provided with special dependencies. See Controllers below for a list of these special dependencies.
The run method accepts a function, which can be injected with "service", "value" and "constant" components as dependencies. Note that you cannot inject "providers" into run blocks.
The config method accepts a function, which can be injected with "provider" and "constant" components as dependencies. Note that you cannot inject "service" or "value" components into configuration.
So each type of angular component has its own list of acceptable components to inject. Since services are singletons, it really wouldn't make any sense to inject a value as part of a resolve. If you had two separate places on your page that used a service with different resolves, the outcome would be indeterminate. It would make no more sense than injecting $scope into your service. It makes sense for controllers because the controller is responsible for the same area of the page that is being resolved.
If your someService needs to use the data in model, it should have a function that takes the data as a parameter and your controller should pass it.

Related

How exactly works this AngularJS factory example? Some doubts

I am absolutly new in AngularJS and I am studying it on a tutorial. I have a doubt related the use of the factory in Angular.
I know that a factory is a pattern used to create objects on request.
So in the example there is the following code:
// Creates values or objects on demand
angular.module("myApp") // Get the "myApp" module created into the root.js file (into this module is injected the "serviceModule" service
.value("testValue", "AngularJS Udemy")
// Define a factory named "courseFactory" in which is injected the testValue
.factory("courseFactory", function(testValue) {
// The factory create a "courseFactory" JSON object;
var courseFactory = {
'courseName': testValue, // Injected value
'author': 'Tuna Tore',
getCourse: function(){ // A function is a valid field of a JSON object
alert('Course: ' + this.courseName); // Also the call of another function
}
};
return courseFactory; // Return the created JSON object
})
// Controller named "factoryController" in which is injected the $scope service and the "courseFactory" factory:
.controller("factoryController", function($scope, courseFactory) {
alert(courseFactory.courseName); // When the view is shown first show a popupr retrieving the courseName form the factory
$scope.courseName = courseFactory.courseName;
console.log(courseFactory.courseName);
courseFactory.getCourse(); // Cause the second alert message
});
And this is the code, associated to this factoryController controller, inside the HTML page:
<div ng-controller="factoryController">
{{ courseName }}
</div>
So it is pretty clear for me that:
The factoryController use the courseFactory factory because is is injected
The first thing that happen when I open the page is that an alert mesage is shown because it is called the:
alert(courseFactory.courseName);
Then put into the $scope.courseName property (inside the $scope object) the value of the **courseName field of the courseFactory JSON object).
And here my first doubt. I have that the factory is defined by:
.factory("courseFactory", function(testValue)
that I think it means (correct me if I am doing wrong assertion) that my factory is named courseFactory and basically is a function that retutn the courseFactory JSON object.
So this is creating me some confusion (I came from Java) because in Java I call a factory class and I obtain an instance of an object created by the factory. But in this case it seems to me that doing:
$scope.courseName = courseFactory.courseName;
it seems to me that the courseName is retrieved directly by the courseFactory JSON object and I am not using the courseFactory.
How it exactly works? Why I am not calling some getter on the factory? (or something like this)
To simplify things There are two known methods to create functions ( and methods ) that are Usable among all states ( consider it as creating a function in global scope ) , these are factory and service.
you may want to read this first Factory vs Service
it seems to me that the courseName is retrieved directly by the
courseFactory JSON object and I am not using the courseFactory.
Actually this is partially true , as Angular use DI concept ( depency injection ) , you will have to inject your factory ( which by default returns an object , and corresponding functions as attributes ) , case you don't ; you will not be able to use your factory object methods.
Angular is not magic , it is just most people don't realize the most basic concepts of JavaScript , specially Developers coming from different programming environment such as C# , C++ , or Java
Easy.
When you return the courseFactory object in the factory statement, the injected courseFactory in the controller becomes THAT object. Therefore, when you do $scope.courseName = courseFactory.courseName; in the controller, you are actually referencing to the returned object that is injected into the controller as courseFactory. So you don't need a getter, because the courseFactory in your controller is already the object. You can do a console.log(courseFactory); in your controller to see what the courseFactory is. Hope this helps.
When an Angular application starts with a given application module,
Angular creates a new instance of injector, which in turn creates a
registry of recipes as a union of all recipes defined in the core "ng"
module, application module and its dependencies. The injector then
consults the recipe registry when it needs to create an object for
your application.
Ref. https://docs.angularjs.org/guide/providers
Factory is a Singleton service. When you inject the factory in the controller or in any other factory, u get the exact json object which u have defined. It will not create any new instance every time you call it. Factory is initialized only once

Angularjs simple meaning of module and Dependency

Hello I am New to angularjs
var app = angular.module('app', [])
app.controller('ProductController', ['$scope,$htttp', productController]);
Please correct me if i am wrong
This above two line is saying we have created the module name app
and we have controller called productController and have $scope, $http as a dependency.
App is starting point of our angularjs application.
Controller is basically for business logic.
what is the servieces ,Factory ?
what is Dependency Injection in simple words ?
I want to understand it more clearly as i study on angualar.js also. but unable to understand it clearly.
Please help to provide me some simple understanding on this
angular.module create module for application, and an application can one or more than one module. It's for modularity. so if you want to initialize core module. then you have to
var app=angular.module("core.module", [
/* Shared Modules */
"services",
"widgets",
"layout"])
So what it does it will initialize every module for application.so by using app object you can directly create common directive for all the modules and much more.
core.module is behaves like constructor and what you want to initialize will pass in "[]" during the call of constructor. it's up-to you.
You can call it as dependency.
In every module you can have different controllers but one thing always keep in mind whenever you add script file reference in html then do add child modules first then core otherwise it will give error. Module not defined.
Service and Factory pretty much they both are equivalent. Most important is to realize that both are singletons.
Factories are functions that return the object, while services are constructor functions of the object which are instantiated with the new keyword.
Services:
angular.module('app').service('abcservice', function() {
this.getdata= function() {};
});
Factory:
angular.module('app').factory('TestFactory', function() {
return {
someFunction: function() {}
};
});
when you want to use services and factory in our application then you have to pass it as argument/dependency in controller declaration.
app.controller(controllerId, ['$scope','abcservice','TestFactory']);
For much please refer Angular Tutorial

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.

AngularJS DI for custom functions

I've been working a lot lately with AngularJS and I really like the dependency injection stuff. I'm using it all over the place, but just in Angular components, like controllers and the like.
This always calls on the angular object:
angular.module('app').controller(/**/);
Now I have this function:
var custom = function(MyService) {
// do stuff
};
I've declared the Service this way:
angular.module('app').factory('MyService', function($rootScope) {
return {
show: function() {
// do stuff
};
},
hide: function() {
// do stuff
}
};
});
I now want to use this service in my custom function. Is there a way of manually calling the angular DI container? (I couldn't find anything in the docs...)
I know that this works for controllers not defined with the angular.module()... thing:
function Controller(MyService) {
MyService.hide(); // works
}
But how to use it outside of AngularJS components, in completely independent functions?
Or do I have to take a completely different path to achieve my goal?
Cheers and thanks in advanced,
Christian
angularjs is pretty neat in the fact that it exposes its own internal services to the user. The service you're looking for is $injector
What you want to use to call your custom function is $injector.invoke(myCustomFunction,thisForCustomFunction,{named:locals});
If you are by chance wanting to invoke this function outside of angular you'll have to get the applications injector.
var injector = angular.element(elementWithNgApp).injector();
Note:
The invocation time may be reduced though. As the injector must annotate (find what services you need) using several regular expressions. The reason this is not an issue throughout angular is because it is done once. Because services,factories,providers, are all instantiated (newed) singletons that provide closure with the services and whatever uses the services inside your providers
To prevent this extra step you can provide a $inject property on your function.. Something like this:
myfunction.$inject = ['ServiceA','ServiceB'];
function myfunction(a,b){
//a is ServiceA
//b is ServiceB
};

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