How to create Dynamic factory in Angular js? - javascript

In my project i have to create dynamic factory in angular js with dynamic factory name like below
function createDynamicFactory(modId) {
return myModule.factory(modId + '-existingService', function (existingService) {
return existingService(modId);
});
}
I want to get new factory with dynamic name , when i called this function. unfortunately this is not working. how can i achieve this? and how to inject in my controller or in directive dynamically?

You can annotate your service generator like this. It takes the module and extension and then annotates a dependency on the "echo" service (just an example service I defined to echo back text and log it to the console) so the generated service can use it:
makeService = function(module, identifier) {
module.factory(identifier+'-service', ['echo', function(echo) {
return {
run: function(msg) {
return echo.echo(identifier + ": " + msg);
}
};
}]);
};
Then you can make a few dynamic services:
makeService(app, 'ex1');
makeService(app, 'ex2');
Finally, there are two ways to inject. If you know your convention you can pass it in with the annotation as the ext1 is shown. Otherwise, just get an instance of the $injector and grab it that way.
app.controller("myController", ['ex1-service',
'$injector',
'$scope',
function(service, $injector, $scope) {
$scope.service1 = service.run('injected.');
$scope.service2 = $injector.get('ex2-service').run('dynamically injected');
}]);
Here is the full working fiddle: http://jsfiddle.net/jeremylikness/QM52v/1/
Updated: if you want to create the service dynamically after the module is initialized, it's a few slight changes. Instead of trying to register the module, simply return an annotated array. The first parameters are the dependencies and the last is the function to register:
makeService = function(identifier) {
return ['echo', function(echo) {
console.log("in service factory");
return {
run: function(msg) {
return echo.echo(identifier + ": " + msg);
}
};
}];
};
Then you get a reference to the array and call instantiate on the $injector to wire it up with dependencies:
var fn = makeService('ex2');
$scope.service2 = $injector.instantiate(fn).run('dynamically injected');
Here's the fiddle for that version: http://jsfiddle.net/jeremylikness/G98JD/2/

Related

Dynamically add properties/function to a service/factory

I wrote a small Angular1 app which has a Database service that is using LokiJS.
I was wondering if there is a way to dynamically add properties/functions to a Service/Factory.
I'm trying to add dynamic getter for every collection that is created via this Service.
Here my example:
Database.js
angular.module('MyApp')
.factory('Database', ['$log', '$q', 'Loki',
function Database($log, $q, Loki)
{
var _db,
dbInitialized = false;
function init(config)
{
// some logic here
}
function addCollection(name, cfg) {
// some logic here
_db.addCollection(name, cfg);
// this doesnt work, but is desired ->
/*this['get'+name] = this.getCollection.bind(this, name);*/
}
function getCollection(collectionName) {
// some logic here
return something;
}
return {
init: init,
addCollection: addCollection,
getCollection: getCollection
};
}
]
);
app.js
angular
.module('MyApp', ['lokijs'])
.run(['Database',
function (Database) {
Database.init();
Database.addCollection("MyCollection", {});
// then fill collection, afterwards ->
var collection = Database.getCollection("MyCollection");
// I would like to use Database.getMyCollection()
}]);;
Is there a way to modify a initialized Service/Factory?
The most appropriate place for that is decorator
app.decorator('Database', ['$delegate', function ($delegate) {
var Database = $delegate;
Database.init();
Database.addCollection("MyCollection", {});
...
return Database;
}]);
The recipe doesn't really differs from run block, but it guarantees that service will be initialized on injection, while run blocks depend on their order.

Angular pass data between controller

I have requirement where i need to share data between controllers,so i created factory
suppose i have url like: abc/123 (Note:123 is dynamic i need to pass it from controller)
MyCode
appServices.factory('classesService', function($http){
return {
getClasses: function(value) {
return $http.get(urlprefix + 'orgs/' + value + '/classes?with-users=true');
}
};
});
In Controller
classesService.getClasses($scope.organization.id).then(function(data){});
now suppose i am using it in 3 contollers 3 calls will go to server. i dont want three calls i want only one call.
Note:value is same for all three controller
is there any way i can acheive this.
Thanks
You can use UI-ROUTER-EXTRAS "https://christopherthielen.github.io/ui-router-extras/#/home"
The easiest solution is to just enable caching in your service. This way all your controllers can access the method and the request is made only once.
return $http.get(urlprefix + 'orgs/' + value + '/classes?with-users=true', {cache: true});
This is very basic caching. You may need a more advanced strategy -- but this is your first step.
UPDATE
You may run into a race condition with simple $http caching if your second or third request are made before the first request completes. We can overcome this easily.
appServices.factory('classesService', function($http) {
var orgsPromise;
return {
getClasses: function(value) {
if (orgsPromise) return orgsPromise;
orgsPromise = $http.get(urlprefix + 'orgs/' + value + '/classes?with-users=true');
return orgsPromise;
}
};
});
I believe you can do something like this;
var yourApp = angular.module('yourApp',[]);
yourApp.factory('classesService', function($http){
var classes;
return {
getClasses: function(value) {
if (!classes) {
classes= $http.get(urlprefix + 'orgs/' + value + '/classes?with-users=true');
}
return classes;
}
};
});
yourApp.factory('Classes', ['classesService',function(classesService){
return classesService.getClasses();
}]);
function yourControllerA($scope, Classes) {
$scope.value="Hello from Controller A";
$scope.sharedValue=Classes;
....
}
function yourControllerB($scope, Classes) {
$scope.value="Hello from Controller B";
$scope.sharedValue=Classes;
....
}
function yourControllerC($scope, Classes) {
$scope.value="Hello from Controller C";
$scope.sharedValue=Classes;
....
}

Angular: Updating scope with factory service

I'm currently having an issue with keeping my scopes updated using a factory service and AngularFire. I think the code speaks for itself:
//Creates firebase object based on URL ($stateParams as an ID)
jobControllers.factory('Job', getJobService);
function getJobService($firebaseObject, $stateParams) {
var ref = new Firebase("<my firebase url>" + $stateParams.jobId);
return $firebaseObject(ref);
}
//Sets Scope to firebase object in getJobService
jobControllers.controller('JobCtrl', function ($scope, $location, Job) {
$scope.job = Job;
});
This works fine, when you click a link like /jobs/:jobId/ it loads the proper data. The problem is once you go back to /jobs/ and click another :jobId the data remains the same. I am fairly certain the issue is that my firebase URL is staying the same and $stateParams isn't changing on controller load so the data uses the URL For the first item clicked. If this is the case, how can I change my factory to take a parameter so I can pass the correct updated $stateParams to it in the controller?
I previously did not have this problem when I had called my firebase objects inside the controller as such:
jobControllers.controller('JobCtrl', function ($scope, $location, $stateParams, $firebaseObject) {
var ref = new Firebase("<my firebase url>" + $stateParams.jobId);
$scope.job = $firebaseObject(ref);
});
My reasoning for using a factory is because I did not like how I was defining the firebase URLs in every different controller, so I wanted to create a reusable service for such. If there is a better way - please advise.
edit: Figured it out thanks to charlieftl
function getFireBaseService($firebaseArray, $firebaseObject) {
return {
getArray: function(url) {
var ref = new Firebase("https://<my-app>.firebaseio.com" + url);
return $firebaseArray(ref);
},
getObject: function(url) {
var ref = new Firebase("https://<my-app>.firebaseio.com" + url);
return $firebaseObject(ref);
}
}
}
The problem is the factory is a singleton and only initializes once. Your approach will only use whatever value $stateParams.jobId is when it does initialize
Use a function to return the firebase object so that it will be run each time it is called upon
function getJobService($firebaseObject, $stateParams) {
function getJob() {
var ref = new Firebase("<my firebase url>" + $stateParams.jobId);
return $firebaseObject(ref);
}
//return object from factory
return {
getJob: getJob
}
}
Then in controller
$scope.job = Job.getJob();

AngularJs: Calling Service/Provider from app.config

I would like to call my service from within app.config.
When searching for this, I found this question with a solution that i tried to follow (not the accepted answer, but the solution below with the title "Set up your service as a custom AngularJS Provider")
However with that solution and with the suggested alternative as well i run into problems when i am trying to call the service from within my app.config (The service does not seem to be called at all). I am new to angular and javascript and don't really know how to debug this properly (i am using firebug). I hope you can help me with some pointers and possibly a solution.
Current Code (trying to implement the "possible alternative" from the linked question:
angular.module('myApp', [
'ngRoute',
])
.config(['$routeProvider', '$locationProvider', '$provide', function($routeProvider, $locationProvider, $provide) {
$provide.service('RoutingService',function($routeParams){
var name = $routeParams.name;
if (name == '') {name = 'testfile'}
var routeDef = {};
routeDef.templateUrl = 'pages/' + name + '/' + name + '.html';
routeDef.controller = name + 'Ctrl';
return routeDef;
})
//Here i would like to get a hold of the returned routeDef object defined above.
$routeProvider.when('/name:', {
templateUrl: RoutingService.templateUrl,
controller: RoutingService.controller
});
My previous attempt was to declare the Service like this via a provider:
var ServiceModule = angular.module('RoutingServiceModule', []);
ServiceModule.provider('routingService', function routingServiceProvider(){
this.$get = [function RoutingServiceFactory(){
return new RoutingService();
}]
});
function RoutingService(){
this.getUrlAndControllerFromRouteParams = function($routeParams){
var name = $routeParams.name;
var routeDef = {};
routeDef.templateUrl = 'pages/' + name + '/' + name + '.html';
routeDef.controller = name + 'Ctrl';
return routeDef;
}
}
and tried to call it like i would usually call a service in a controller (after adding the RoutingServiceModel to the dependencies of myAppof course). In both cases the templateUrl and controller are not set when i navigate to my views, so I guess i am missing some dependencies, or am not calling the service correctly.
Any ideas?
during the config phase, only providers can be injected (with the
exception of the services in the AUTO module--$provide and $injector).
Please check this working demo: http://jsfiddle.net/nxbL66p2/
angular.module('Joy',[])
.config(function($provide) {
$provide.provider('greeting', function() {
this.$get = function() {
return function(name) {
alert("Hello, " + name);
};
};
});
})
.controller('MyCtrl', ['$scope', 'greeting', function ($scope, greeting) {
$scope.greet = function () {
greeting('Joy');
};
}]);
Simple HTML:
<div ng-app="Joy">
<div ng-controller="MyCtrl">
<div ng-click="greet()">Click to greet.</div>
</div>
</div>
Reference: https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
Angular's terminology is a bit of a mess, because 'service' and 'provider' may designate different things, depending on the context. According to the statement in the manual,
An Angular service is a singleton object created by a service factory.
These service factories are functions which, in turn, are created by a
service provider. The service providers are constructor functions.
When instantiated they must contain a property called $get, which
holds the service factory function.
You can't inject services in config (except constant), only service providers, and your RoutingService is inapplicable there.
Technically, you can get a service there with
RoutingServiceProvider.$get();
But it will make a separate instance (rather than singleton object), and the usage of $routeParams makes no sense at the moment when it is being called in config.
You can have templateUrl as function (see the manual), while dynamic controller names aren't suitable for route configuration, define them within templates with ng-controller instead.

inheritance with angularjs .service()

I have a ServiceA() in module A and variable item is used in html.
angular.module("ModuleA").service("ServiceA", function () {
var item=[];
this.get(){
item.push("A");
}
});
Controller.js
angular.module("ModuleX").controller("Ctrl", function (ServiceA) {
$scope.service=ServiceA;
});
HTML:
<h1>{{service.item}}
</h1>
i am trying to achieve inheritance using angularjs .service(),I want to make serviceA() in moduleA as base service and create a service serviceB() in moduleB and this should inherit base service(serviceA()) and update variable 'item' in serviceA().
Controller code and html code remains same.
Is it possible? Is this a good approach? Can we achieve inheritance/abstraction using angularjs .service()?
angular.module("ModuleB").service("serviceB", function (serviceA) {
serviceA.item="B";
});
Whenever you define a module, you should pass a empty array or
dependencies as the second argument. i.e. angular.module("ModuleA",
[]) or angular.module("ModuleA", ['someDependent']).
The service is in one module whereas the controller is in the other module. So, you need to create a relation between them angular.module("ModuleX", ["ModuleA"]).
You are not returning anything from the service and you have written the method in wrong way.
Plnkr
Working Code
angular.module("ModuleA", []).service("ServiceA", function () {
var item=[];
this.get = function(){
item.push("A");
return item;
}
});
angular.module("ModuleX", ["ModuleA"]).controller("Ctrl", function ($scope, ServiceA) {
$scope.service = ServiceA.get();
console.log($scope);
});

Categories

Resources