How to properly overwrite the exceptionHandler in angularjs? - javascript

For an app I'm using a skeleton that is very similar to https://github.com/angular/angular-seed.
I've tried something like this, in services.js:
'use strict';
/* Services */
angular.module('mApp.services', []).
factory('$exceptionHandler', function () {
return function (exception, cause) {
alert(exception.message);
}
});
This doesn't do anything, it doesn't seem to overwrite the exceptionHandler.
If I try:
var mod = angular.module('mApp', []);
mod.factory('$exceptionHandler', function() {
return function(exception, cause) {
alert(exception);
};
});
It overwrite the whole app.
How can I properly overwrite the exceptionHandler if I am using a skeleton similar to the default angular app?

It's hard to know for certain without seeing the rest of your app, but I'm guessing angular.module('myApp').factory( ... will work. If you leave out the second parameter (,[]) angular will retrieve an existing module for further configuring. If you keep it angular will create a new module.

try this example
http://jsfiddle.net/STEVER/PYpdM/
var myApp = angular.module('myApp', ['ng']).provider({
$exceptionHandler: function(){
var handler = function(exception, cause) {
alert(exception);
//I need rootScope here
};
this.$get = function() {
return handler;
};
}
});
myApp.controller('MyCtrl', function($scope, $exceptionHandler) {
console.log($exceptionHandler);
throw "Fatal error";
});

Related

I have an empty function that's deregistering my controllers in Angularjs

Using Angularjs 1.6.3, I have a controller like this:
'use strict';
var ngnControllers = angular.module('ngnControllers');
ngnControllers.controller('TestCtrl', ['$scope', '$location', '$http',
function TestCtrl($scope, $location, $http) {
console.log("Before defining $scope.play()");
$scope.play() = function() {
};
console.log("After defining $scope.play()");
}
]);
I copied the $scope.play() function from another controller where it was having the same effect:
When it is not commented out, I get a message saying that the controller is not registered, but that's all. When it is commented out everything works fine.
I am at a loss. Any ideas?
Because your function declaration syntax is wrong and as a result is throwing an error. The error gets caught internally and simply causes the controller registration to fail
Change:
$scope.play() = function() {
To
$scope.play = function() {
You should have empty dependencies added to your module,
var ngnControllers = angular.module('ngnControllers',[]);

JasmineJS: Test angular factory with dependencies

I have a factory defined like this:
angular.module("myServices")
.factory("$service1", ["$rootScope", "$service2", function($rootScope, $service2){...})];
Now, I want to test it, but just injecting $service1 is not working because i get an 'unknown provider' error. So I tried something like that. But I still can't make it work. Why?
beforeEach(function() {
module("myServices");
inject(function ($injector) {
dependencies["$service2"] = $injector.get("$service2");
});
module(function($provide) {
$provide.value("$service1", dependencies["$service2"]);
});
inject(function($injector) {
factory = $injector.get("$service1");
});
});
This is what's working in my tests, using underscores:
describe('Service: $service1', function () {
var $service2, scope;
beforeEach(inject(function (_$service2_, $rootScope) {
$service2 = _$service2_;
scope = $rootScope;
}));
//tests
});
If that still doesn't work, then maybe you're not loading the relevant files (such as service2.js) in your tests.

AngularJS - How to limit service visibility?

I'm trying to create an angular service which will be visible only in some modules (but not in all). I have tried to create a service in a module and then include it in a different module, but the service is still visible in the entire application.
Example:
var myAppSubModule = angular.module('myAppSubModule',[]);
myAppSubModule.factory('TestSubService', function() {
return {
testFnc: function() {
return 'test';
}
}
});
var myAppModule = angular.module('myAppModule',['myAppSubModule']);
myAppModule.factory('TestService', function(TestSubService) {
return {
testFnc: function() {
return TestSubService.testFnc(); //this should work
}
}
});
var myApp = angular.module('myApp',['myAppModule']);
function MyCtrl($scope, TestSubService, TestService) {
$scope.name = TestService.testFnc(); //this should work
$scope.name2 = TestSubService.testFnc(); //this should fail
}
I want TestSubService to be visible in TestService, but not in the entire application.
Is there any way to achieve this?

AngularJs/ .provider / how to get the rootScope to make a broadcast?

Now my task is to rewrite $exceptionHandler provider so that it will output modal dialog with message and stop default event.
What I do:
in project init I use method .provider:
.provider('$exceptionHandler', function(){
//and here I would like to have rootScope to make event broadcast
})
standart inject method does not work.
UPD: sandbox - http://jsfiddle.net/STEVER/PYpdM/
You can inject the injector and lookup the $rootScope.
Demo plunkr: http://plnkr.co/edit/0hpTkXx5WkvKN3Wn5EmY?p=preview
myApp.factory('$exceptionHandler',function($injector){
return function(exception, cause){
var rScope = $injector.get('$rootScope');
if(rScope){
rScope.$broadcast('exception',exception, cause);
}
};
})
Update: add .provider technique too:
app.provider('$exceptionHandler', function() {
// In the provider function, you cannot inject any
// service or factory. This can only be done at the
// "$get" method.
this.$get = function($injector) {
return function(exception,cause){
var rScope = $injector.get('$rootScope');
rScope.$broadcast('exception',exception, cause);
}
};
});
My way of doing this - using a decorator and reverting to the previous exception handler on unknown errors:
app.config(function ($provide) {
$provide.decorator('$exceptionHandler', function($delegate, $injector) {
return function (exception, cause) {
if (ICanHandleThisError) {
var rootScope= $injector.get('$rootScope');
// do something (can use rootScope)
} else
$delegate(exception, cause);
};
});
});
You need to inject the $rootScope:
.provider('$exceptionHandler', '$rootScope', function(){
//and here I would like to have rootScope to make event broadcast
})
Is this what you tried? And if so do you have an error message or a jsfillde/plnkr to see why it failed?

Angularjs - what I'm doing wrong with injections?

In my previous question I got an answer hot to inject dependencies and while I tested it, everything worked well. Then I refactored the code and wanted to start the app implementation, but the injections stopped to work :(
http://jsbin.com/alemik/1/edit
In addittion to jsbin, here is the source:
var ABCS = angular.module("ABCS", []);
ABCS.Configuration = angular.module('ABCS.Configuration', []);
ABCS.Controllers = angular.module('ABCS.Controllers', []);
ABCS.Modules = angular.module("ABCS.Modules", []);
ABCS.Services = angular.module("ABCS.Services", []);
ABCS.run(["$rootScope", "$location", "ABCS.Services.LogService",
function ($rootScope, $location, logger) {
logger.log("app start");
}]);
ABCS.Configuration.factory("Environment", function () {
return {
logOutputElementId: "output",
hasConsole: console && console.log
}
});
//Log service
ABCS.Services.LogService = function (config) {
this.log = function (message) {
if (typeof (config.Environment.logOutputElementId) === "string") {
document.getElementById(config.Environment.logOutputElementId).innerHTML += message + "<br/>";
}
else if (config.Environment.hasConsole) {
console.log(message);
}
else {
alert(message);
}
};
};
ABCS.Services.LogService.$inject = ["ABCS.Configuration"];
ABCS.Services.factory("ABCS.Services.LogService", ABCS.Services.LogService);
What I miss? Why ABCS.Services.LogService can not be injected in current structure.
Thanks
When you've got several modules, you need to make sure that you declare your modules' dependencies. This tells the dependency injector to look in those modules when looking for providers.
var ABCS = angular.module("ABCS", [
'ABCS.Services', 'ABCS.Configuration', 'ABCS.Controllers',
'ABCS.Modules', 'ABCS.Services'
]);
I had to make a few more adjustments to get it working:
The dependency injector won't inject an entire module, and so ABCS.Services.LogService.$inject = ["ABCS.Configuration"]; wasn't working. I've changed that to ABCS.Services.LogService.$inject = ["ABCS.Configuration.Environment"]; and adjusted the associated factory in order to fit your naming conventions.
factory accepts a function, but won't call it as a constructor, and thus using this in your definition of LogService won't act as you are expecting it to. I've changed your factory function to define a constructor function, which is then instantiated and returned.
See a working version here: http://jsbin.com/alemik/2/edit
In my opinion , that's the angularJS way of doing things ( though i kept all the DI definitions ):
angular.module("ABCS", ['ABCS.Services', 'ABCS.Configuration', 'ABCS.Controllers', 'ABCS.Modules', 'ABCS.Services']);
angular.module('ABCS.Configuration', []);
angular.module('ABCS.Controllers', []);
angular.module("ABCS.Modules", []);
angular.module("ABCS.Services", []);
angular.module("ABCS").run(["$rootScope", "$location", "ABCS.Services.LogService",
function ($rootScope, $location, logger) {
logger.log("app start");
}]);
angular.module('ABCS.Configuration').factory("ABCS.Configuration.Environment", function () {
return {
logOutputElementId: "output",
hasConsole: console && console.log
};
});
angular.module("ABCS.Services").factory("ABCS.Services.LogService",["ABCS.Configuration.Environment",function (environment) {
function LogService() {
this.log = function (message) {
if (typeof (environment.logOutputElementId) === "string") {
document.getElementById(environment.logOutputElementId).innerHTML += message + "<br/>";
}
else if (environment.hasConsole) {
console.log(message);
}
else {
alert(message);
}
}
}
return new LogService();
}]);
angularJS allows to reopen a module definition in multiple files , and javascript namespacing is totally unecessary unless the object is not tight to the angularJS application.
Mixing javascript namespacing and DI namespacing makes code more error prone ,not more maintanable.

Categories