Why does i can't inject services like this?
service('actionService',function (sessionService) {
this.doAction = function () {
return 5;
}
});
service('sessionService',function (userService) {
this.get = function {
if(userService.check()){
//do other stuffs
}
}
});
service('userService',function (actionService) {
this.check = function () {
actionService.doAction();
if(x = 9){
return true;
}else{
return false;
}
}
});
I get "Circular injection error" in console
how to handle this now ?
here a better code : http://pastebin.com/wS32UNCq
Before you can have an instance of actionService, you need to inject an instance of sessionService.
Before you can have an instance of sessionService, you need to inject an instance of userService.
Before you can have an instance of userService, you need to inject an instance of actionService.
It's a chicken or the egg problem... because Angular uses constructor injection, it can't instantiate a service until all of its dependencies are satisfied. But the dependencies go around in a circle, none of them can ever be instantiated.
To solve this problem, you will need to extract a shared dependency out to an additional service which can be instantiated without dependencies.
Related
I am having one condition i.e
if(localstorage.testEnv){
env.apiUrl='testUrl.com';
}else{
env.apiUrl='liveUrl.com';
}
I need to inject this code in all the services. Is there any way I can implement this so that their won't be any code duplication.
Also, would this code work? I am trying to update env const (apiUrl) here?
Simplest way is to make a Utils Service and expose all common functions in this file, in this case a function which checks testEnv from local Storage and returns the corresponding URL. In this case getAPIBaseUrl is the function.
define(["../module"], function(services) {
"use strict";
services.service("Utils", [
"$localStorage",
function($localStorage) {
this.getAPIBaseUrl = function() {
if ($localStorage.testEnv) {
return "testUrl.com";
}
return "liveUrl.com";
};
}
]);
});
Unless the API url can change in the runtime, you may want to define the apiUrl and an AngularJS constant.
var app = angular.module('app', []);
app.constant('apiUrl', (function() {
return localStorage.testEnv ? 'testUrl.com' : 'liveUrl.com'
})());
app.controller('SomeController', function(apiUrl) {
console.log(apiUrl)
});
Main benefit of using a constant is that it can be injected in the configuration phase, e.g:
app.config(function(apiUrl) {
console.log(apiUrl)
})
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.
Stack:
Typescript 1.7 + Angular 1.49
Summary:
I have a directive. I want to $inject angular's $timeout service. It works fine in the directive's controller function, but not in the link function. What am I missing?
Questions:
What did I do wrong?
Is there a better way to $inject the $timeout dependency?
Why will the $timeout service work in the directive's controller but not the link?
MyDirective.ts:
module app.directives {
export class MyDirective {
priority = 0;
restrict = 'E';
templateUrl = 'template.html';
scope = {
'items': '='
};
controller = MyController;
link = MyLink;
static $inject = ['$timeout'];
constructor(private $timeout:ng.ITimeoutService) {
}
}
function MyController($scope:ng.IScope, $timeout:ng.ITimeoutService) {
console.log("controller", $timeout); // function timeout(fn,delay,invokeApply){ the guts here }
$timeout(function () {
console.log("This works fine");
},3000);
}
function MyLink(scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, $timeout:ng.ITimeoutService) {
console.log("link to", $timeout); // MyController {}
$timeout(function () {
console.log("This throws the error, TypeError: $timeout is not a function");
},3000);
}
}
Connecting it in directives.ts:
module app.directives {
angular.module('app').directive('MyDirective',['$timeout',($timeout:ng.ITimeoutService) => new MyDirective($timeout) ]);
}
app.ts
module app {
angular.module('app', []);
}
What hasn't worked:
Using this.$timeout in MyLink, with or without including $timeout in the parameters.
I've found several articles and examples that I've tried to make sure I'm following the logic of in my app but can't seem to get it.
Final notes
Typescript-Angular is still new and there are so many best practices that are far from being defined. Part of my team's project is finding some of those.
We have been working on this general structure for a while, so unless there's a compelling reason, please refrain from suggestions that I change the structure of everything too much.
Link functions are not executed directly from directive instance, hence you wont get this as Directive's config instance (which you instantiate via new operator). Also you cannot inject anything to the link function (that is what directive constructor is for) unlike the controller constructor, the arguments to the link function are automatically passed in by the directive execution logic. You could use an arrow operator to resolve this issue.
Example:
export class MyDirective {
priority = 0;
restrict = 'E';
templateUrl = 'template.html';
scope = {
'items': '='
};
controller = MyController;
link:ng.IDirectiveLinkFn = (scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes) => {
//Here
this.$timeout(function () {
},3000);
};
constructor(private $timeout:ng.ITimeoutService) {
}
}
Or you could bind the context using function.bind. i.e link = MyLink; and access the $timeout using this.$timeout.
If interseted you could take a look at creating some syntactic sugars by using experimental decorators for directives or you could try exploring something like this. However (just my opinion) using a class for directive config seems to be an overkill, you might as well just use a function with static inject.
Link function 4th parameter is the controller instance him self.
If you want to do it you should do something like:
module app.directives {
export class MyDirective {
link = MyLink;
static $inject = ['$timeout'];
constructor(public $timeout:ng.ITimeoutService) {
}
}
function MyLink(scope:ng.IScope, element:ng.IAugmentedJQuery, attr:ng.IAttributes, ctrl:any) {
ctrl.$timeout(function () {
console.log("This throws the error, TypeError: $timeout is not a function");
},3000);
}
}
I know that this is not elegant but I have hard time finding a better solution, what do you think?
I assume there's a straightforward (maybe trivial) answer for this that I just haven't wrapped my head around.
Why does this do what I want -- that is, inject a reference to $provide into my service:
angular.module('error_reporting', [])
.provider('RaygunLogger', function() {
var provide = undefined;
this.setProvide = function(p){
provide = p;
}
this.$get = function() {
// use $provide in p
};
})
.config(function(RaygunLoggerProvider, $provide) {
RaygunLoggerProvider.setProvide($provide);
});
while this produces an error of the form Unknown provider: $provideProvider <- $provide <- RaygunLogger <- RaygunLogger?
angular.module('error_reporting', [])
.provider('RaygunLogger', function() {
this.$get = function($provide) {
// use $provide
};
});
Is RaygunLogger.$get() running before the injector is set up? I presume this is an order-of-operations issue, where I need to wait until the module config phase before I can inject $provide, but I don't know where to verify that in the doc.
$provide is only available during the config phase. Provider's $get function is run after the config phase to create the thing the provider provides.
At this point, you cannot do what you are trying to do.
To use it inside $get your normally start your provider function with
var self = this;
and in $get (factory) definition you use self.
E.g
angular.module('foo',[])
.provider('myFoo', function myFooProviderFn() {
var self = this;
self._debug = false;
self.setDebug = function() { self._debug = true; }
self.$get = ['$location', function($location) {
self.setDebug();
});
});
Its wrong to think you cannot use it inside your $get. As such the actual pure provider instance can only be accessed and manipulated during the config phase. The rationale behind this design is probably that providers are thought of to be some mechanism to configure factories.
More from the docs (Provider recipe)
I'm using a framework called Radiant UI, which is a way to get HTML5 UI into Unreal Engine 4. I'm trying to pick up some modern Javascript while I do that, so I'm building the UI in AngularJS.
My understanding of Angular is still pretty weak though, and I'm a bit confused about what the best practice is here. The extension injects the following Javascript when it sets up.
var RadiantUI;
if (!RadiantUI)
RadiantUI = {};
(function() {
RadiantUI.TriggerEvent = function() {
native function TriggerEvent();
return TriggerEvent(Array.prototype.slice.call(arguments));
};
RadiantUI.SetCallback = function(name, callback) {
native function SetHook();
return SetHook(name, callback);
};
RadiantUI.RemoveCallback = function(name) {
native function RemoveHook();
return RemoveHook(name);
};
})();;
So this is simply pushing RadiantUI into the global namespace. That would be fine if the extension was always there, but it isn't. In the test environment (Chrome), it's not there. It's only there when running in the game engine. That, combined with the fact that globals suck, means I want to encapsulate it.
In the previous iteration of this, I had it wrapped in an AMD module, and it worked well. Like this:
define([], function()
{
if ("RadiantUI" in window)
{
console.log("RadiantUI in global scope already!");
return window.RadiantUI;
}
var RadiantUI;
if (!RadiantUI) {
RadiantUI = {};
RadiantUI.TriggerEvent = function() {}
RadiantUI.SetCallback = function() {}
RadiantUI.RemoveCallback = function() {}
}
console.log("Using fake RadiantUI bindings");
return RadiantUI;
});
So here's what I want to do:
I want to include radiant as a dependency to my app/stateProvider and have it injected, much the same way it would be in AMD. With the stub methods in place if the extension isn't present. What's the proper approach to this? A module? A service provider?
UPDATE: This is the working code using the answer given.
var myapp = angular.module('bsgcProtoApp', ['ui.router' ]);
myapp.value('radiant', window.RadiantUI || {
TriggerEvent: function()
{
console.log("TriggerEvent called");
},
SetCallback: function(name, callback)
{
console.log("Setcallback called");
},
RemoveCallback: function(name)
{
console.log("RemoveCallback called");
}
});
myapp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider )
{
$urlRouterProvider.otherwise("/mainmenu");
$stateProvider.state('mainmenu',
{
name: "mainmenu",
url: "/mainmenu",
templateUrl: 'templates/mainmenu.html',
controller: ['$scope', 'radiant', function($scope, radiant)
{
$scope.tester = function()
{
radiant.TriggerEvent("DuderDude");
console.log("Duder!");
}
}],
});
}]);
You presumably have an Angular module or app. For the sake of this answer, let's call it MyApp.
Now you can do
MyApp.value("RadiantUI", window.RadiantUI || {
TriggerEvent = function(){},
//... more properties
});
Now to access this value as a dependency in a controller for example, you'd do this
MyApp.controller(["$scope", "RadiantUI", function($scope, RadiantUI){
// ... controller code ...
}]);