i'm newbie in angular js, have created a project in angular js and want to maintain log on server for all the issues occuring at the client side.
Gone through various blogs and found few suggestions for applying stack js but couldn't understand the implementation for same.
Please suggest if it is possible to log all the errors in project from one single point of client side, at the server through factory or service method using angular js.
This is possibly by overriding angulars built in $exceptionHandler. Below is the snippet of code from my own app that logs any failures to the backend, but also prints them into the console, in case the backend logging fails. As my javascript is minified, I use StackTrace to turn this back into an un-minified stack trace, and send that to my backend.
function exceptionLoggingService($injector) {
function error(exception, cause) {
// preserve the default behaviour which will log the error
// to the console, and allow the application to continue running.
var $log = $injector.get('$log');
var $window = $injector.get('$window');
$log.error.apply($log, arguments);
var errorMessage = exception.toString();
StackTrace.fromError(exception).then(function (arrayStack) {
var exceptionData = angular.toJson({
errorUrl: $window.location.href,
errorMessage: errorMessage,
stackTrace: arrayStack,
cause: ( cause || "" )
});
// now post this exceptionData to your backend
}).catch(function (backendLoggingError) {
$log.warn("Error logging failure.");
$log.log(backendLoggingError);
});
}
return(error);
}
angular.module('dashboard-ui').factory('$exceptionHandler', ['$injector', exceptionLoggingService])
Related
I have a simple angular resource that I've defined as below:
CompanyService.factory('CompanyService',
function ($resource) {
return $resource('https://baseurl.com/api/values/');
}
);
I then have a controller that calls that resource passing in a success and fail function:
.controller('companyList', function($scope, CompanyService) {
$scope.companies = CompanyService.query(
function(data) {
console.log(data);
return data;
},
function(error){
console.log("Error:");
console.log(error);
}
);
The rest API is a .NET MVC Web API that is extremely basic. I've configured it to return JSON and it simply returns an array of two objects like below. I've also enabled CORS so my angular app, which is hosted in a different domain, can call the api.
[{ID:1, Name:"TEST1"}, {ID:2, Name:"TEST2"}]
I've tested the REST call using jquery and just straight call through browser. All was functional (including the cross site scripting when calling from my angular app just using a straight JavaScript HTTP call).
When I try to call the api from my controller however, it always ends up in the error function. The error object contains a data property that is always populated with the string "resource is required|resource is required|undefined"
When I check the network I see no call to the values end point. It's as if the call is failing before ever being made.
If I change out the url to point to some sample REST api like https://jsonplaceholder.typicode.com/users/ it works fine and I'm able to see the call to "users" in the network traffic, which makes me think there is something wrong with my C# REST endpoint, however all my tests to call the REST endpoint outside of angular work successfully.
Can anyone help? I can't find anyone reporting this issues before anywhere on the net.
should the code be the one below? i didn't test it, just guess.
myModule.factory('CompanyService',
function ($resource) {
return $resource('https://baseurl.com/api/values/');
}
)
.controller('companyList', function($scope, CompanyService) {
CompanyService.query(
function(data) {
$scope.companies = data;
console.log(data);
return data;
},
function(error){
console.log("Error:");
console.log(error);
}
);
I ended up rebuilding my angular app from scratch. My first app was from the angular-seed github and had a handful of libraries already added in for testing and other things. One of those things is was was leading to this error as once I started a new project completely from scratch and added in angular and my REST call things worked perfectly. I've already spent too much time working through this so not going to spend any more time identifying exactly what it is but in case anyone else runs into the problem I did want to answer this one and close the book on it.
I am writing end-to-end tests for my AngularJS-based application using Protractor. Some cases require using mocks to test - for example, a network connection issue. If an AJAX request to server fails, the user must see a warning message.
My mocks are registered in the application as services. I want them to be accessible to the tests to write something like this:
var proxy;
beforeEach(function() { proxy = getProxyMock(); });
it("When network is OK, request succeeds", function(done) {
proxy.networkAvailable = true;
element(by.id('loginButton')).click().then(function() {
expect(element(by.id('error')).count()).toEqual(0);
done();
});
});
it("When network is faulty, message is displayed", function(done) {
proxy.networkAvailable = false;
element(by.id('loginButton')).click().then(function() {
expect(element(by.id('error')).count()).toEqual(1);
done();
});
});
How do I implement the getProxyMock function to pass an object from the application to the test? I can store proxies in the window object of the app, but still do not know how to access it.
After some reading and understanding the testing process a bit better, it turned to be impossible. The tests are executed in NodeJS, and the frontend code in a browser - Javascript object instances cannot be truly shared between two different processes.
However, there is a workaround: you can execute a script inside browser.
First, your frontend code must provide some sort of service locator, like this:
angular.module('myModule', [])
.service('proxy', NetworkProxy)
.run(function(proxy) {
window.MY_SERVICES = {
proxy: proxy,
};
});
Then, the test goes like this:
it("Testing the script", function(done) {
browser.executeScript(function() {
window.MY_SERVICES.proxy.networkAvailable = false;
});
element(by.id('loginButton')).click().then(function() {
expect(element.all(by.id('error')).count()).toEqual(1);
done();
});
});
Please note that when you use executeScript, the function is serialized to be sent to browser for execution. This puts some limitations worth keeping in mind: if your script function returns a value, it is a clone of the original object from browser. Updating the returned value will not modify the original! For the same reason, you cannot use closures in the function.
I am trying to run the IBM Watson's Tradeoff Analytics widget to show the trade-off analytics graph in a webpage. The Tradeoff Analytics API is starting properly but when I submit the problem to the show the graph, I get some undefined error.
Here is the sample code that I am using the run the Tradeoff Analytics Widget.
function errorHandler(payload){
alert(payload.errorMessage);
}
function onShowCompleteCB(payload){
alert('show Tradeoff graph complete');
}
function onStartCB(payload){
alert('sending trade-off problem');
var problem = <problem-json>;
taClient.show(problem, onShowCompleteCB);
}
var options = {
dilemmaServiceUrl : <tradeoff-service-url>,
username : <username>,
password : <password>
};
var taClient = new TradeoffAnalytics(options , document.getElementById('watson_widget'));
var s = taClient.subscribe('afterError', errorHandler);
taClient.start(onStartCB);
I also noticed from javascript debugger that HTTP response to the last request returned the reponse header WWW-Authenticate:Basic realm="IBM Watson Gateway Log-in". Moreover I get the following error in javascript console XMLHttpRequest cannot load . No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '' is therefore not allowed access. The response had HTTP status code 401.
Can somebody help me out with what might be going wrong here?
PS: I have cross checked my username and password and they seem to be working fine through REST based API invocation.
Based on your code, you are trying to use the client widget. You need to have a proxy app that will receive the request and use your username and password.
On your client side you will need something like:
HTML:
<div id='DIV_ID'></div>
JS:
taClient = new TA.TradeoffAnalytics({
customCssUrl: 'https://ta-cdn.mybluemix.net/v1/modmt/styles/watson.css',
dilemmaServiceUrl: '/proxy',
profile: 'basic'
}, 'DIV_ID');
taClient.subscribe('afterError', function onError(){ /* on error */});
taClient.start(function onLoad(){ /* on load */});
}
Server side(nodejs):
var tradeoffAnalytics = watson.tradeoff_analytics({
version: 'v1',
username: '<username>',
password: '<password>'
});
app.post('/proxy', function(req, res) {
tradeoffAnalytics.dilemmas(req.body, function(err, dilemmas) {
if (err)
return res.status(err.code || 500).json(err.error || 'Error processing the request');
else
return res.json(dilemmas);
});
});
Above you will find an example of how to implement the proxy using express and the watson-developer-cloud npm module.
There is a full sample you can look in github
We're using angular translate to handle localization of a web site, using our own custom loader that fetches translations from the server. On the server side, we have logic that handles missing translation keys so that we both return something (a translation from a fallback language or the key itself) and reports to the system that the key was requested (so it shows up in the translation UI elsewhere on the site). Now, I'm struggling with building something similar on the client side.
The $translateProvider has a method useMissingTranslationHandler(factory) which we've successfully configured to just log out that a key is missing to the console, using the following:
app.config(function ($translateProvider) {
$translateProvider.useMissingTranslationHandler('translationMissingHandler');
});
app.factory('translationMissingHandler', translationMissingHandler);
translationMissingHandler.$inject = ['$window', '$log', '$http'];
function translationMissingHandler($window, $log, $http) {
return function (translationId) {
var culture = $window.preferredCulture, // workaround for another problem
errorInfo = {
key: translationId,
culture: culture
};
$log.warning('Translation missing:', errorInfo);
// $http.post('/api/v2/localization/missing', errorInfo);
}
}
However, then I uncomment the POST to the server, notifying about the missing key, the page hangs on line 14394 of angular.js - throw e, where e.message is
[$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
I've tried various things to get around this - e.g. wrapping the call to $http.post() in $timeout or $rootScope.$apply but to no avail; I still get the same error message.
Is there a way to schedule a call to $http.post() from here without causing this error? If so, how?
I am fairly new to AngularJS and am trying to learn some best practices. I have things working, but would like to start adding some unit tests to my modules and controllers. The first one I am looking to tackle is my AuthModule.
I have an AuthModule. This Module registers a Factory called "AuthModule" and exposes things like "setAuthenticatedUser" and also fields like "isLoggedIn" and "currentUser". I think this is a fairly common pattern in an AngularJS application, with some variations on the specific implementation details.
authModule.factory(
'AuthModule',
function(APIService, $rootScope) {
var _currentUser = null;
var _isLoggedIn = false;
return {
'setAuthenticatedUser' : function(currentUser) {
_currentUser = currentUser;
_isLoggedIn = currentUser == null ? false : true;
$rootScope.$broadcast('event:authenticatedUserChanged',
_currentUser);
if (_isLoggedIn == false) {
$rootScope.$broadcast('event:loginRequired')
}
$rootScope.authenticatedUser = _currentUser;
$rootScope.isLoggedIn = _isLoggedIn;
},
'isLoggedIn' : _isLoggedIn,
'currentUser' : _currentUser
}
});
The module does some other things like register a handler for the event "loginRequired" to send the person back to the home screen. These events are raised by the AuthModule factory.
authModule.run(function($rootScope, $log, $location) {
$rootScope.$on("event:loginRequired", function(event, data) {
$log.info("sending him home. Login is required");
$location.path("/");
});
});
Finally, the module has a run block which will use an API service I have to determine the current logged in user form the backend.
authModule.run(
function(APIService, $log, AuthModule) {
APIService.keepAlive().then(function(currentUser) {
AuthModule.setAuthenticatedUser(currentUser.user);
}, function(response) {
AuthModule.setAuthenticatedUser(null);
});
});
Here are some of my questions:
My question is how would you setup tests for this? I would think that I would need to Mock out the APIService? I'm having a hard time because I keep getting unexpected POST request to my /keepalive function (called within APIService.keepAlive())?
Is there any way to use $httpBackend in order to return the right response to the actual KeepAlive call? This would prevent me from having to mock-out the API service?
Should I pull the .run() block out which obtains the current logged in user out of the AuthModule and put it into the main application? It seems no matter where I put the run() block, I can't seem to initialize the $httpbackend before I load the module?
Should the AuthModule even be its own module at all? or should I just use the main application module and register the factory there?
Run blocks are the closest thing in Angular to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the service have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests.angularjs docs
I suggest you take a look at this authentication service, using a service is the way to go.
Hopefully this would help ... Good luck