I have to use global variable in angular service.
I have function to get session id from parent application. like this
var sessionID;
function AddSessionID(e) {
sessionId = e;
}
This is the function I have used for get sessionid and this function called in parent app.
I need to use this session id(sessionID) inside angular service as a parameter.
this is my service call
(function () {
"use strict";
mApp.service('compasService', ['$http', '$q', function ($http, $q) {
//Public API
return {
initialLayout: initialLayout
};
function initialLayout() {
var dataObj = {};
dataObj.command = 'getLayoutCstics';
dataObj.sessionID = sessionId;
dataObj.userid = userID;
var transform = function (data) {
return $.param(dataObj);
},
request = $http({
method: "POST",
url: myURL,
//params:For passing via query string
transformRequest: transform,
dataType: "text",
//To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
crossDomain: true
});
return (request.then(successHandler, erroHandler));
}
})();
Please get me a proper way to get it.
Architectually speaking, if you must use global variables, you want to limit the places that must use the global context. In this case, you might benefit from a sessionService in Angular that encapsulates access to the session Id.
(function(global) {
'use strict';
mApp.service("sessionService", function() {
return {
getSessionID: function() {
return global.sessionId;
},
getUserID: function() {
return global.userID;
}
};
});
}(this));
Then you can specify that as a dependency in your other Angular services:
(function () {
"use strict";
mApp.service('compasService', ['$http', '$q', 'sessionService', function ($http, $q, sessionService) {
//Public API
return {
initialLayout: initialLayout
};
function initialLayout() {
var dataObj = {
command: 'getLayoutCstics',
sessionID: sessionService.getSessionID(),
userId: sessionService.getUserID()
},
transform = function (data) {
return $.param(dataObj);
},
request = $http({
method: "POST",
url: myURL,
//params:For passing via query string
transformRequest: transform,
dataType: "text",
//To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
crossDomain: true
});
return (request.then(successHandler, erroHandler));
}
})();
The successHandler and erroHandler appear to be global functions as well. The second function, erroHandler appears to be misspelled and should be errorHandler (notice the "r" before the "H"), though I don't know if the spelling is an actual problem.
The whole point is to encapsulate access to global variables in one or more services so you limit your use of globals in your other services, modules and controllers.
Related
Hi there I write a service of $resource for connecting the api.
here is the code in service.js
.factory('selfApi2', function ($resource, localStorageService) {
var AB = {
data: function (apiURL, header, data, params) {
return $resource("http://localhost:4000/api" + apiURL, null, {
update: {
method: 'POST',
headers: header,
data: data,
params: params
}
});
}
};
return AB;
})
in my controller.js
var header = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var myData = {
'phone': '12345678'
};
selfApi2.data('/tableName',header,{where:{"name":"kevin"}).update(myData, function(result){
console.log("update Kevin's phone succeed",result);
})
it works. But why the variable myData should put inside the update() part rather than the data() part?
In your case, the data() is a function which will just create a ReST resource which would expose rest apis get save query remove delete as default.
So in this data() call you are just creating the rest resources. Passing myData with this function would not make any sense. The data() call would return the Resource instance which will have your update api function which accepts the parameters.
And, passing your data at api construction time does not make sense.
Here is the complete reference
I think it's because "data" is a function that returns object of $resource.
Try the scenario below:
// service
.factory('api', function ($resource) {
var api = {};
api.issues = $resource("http://localhost:4000/api/issues");
api.users = $resource("http://localhost:4000/api/users", {}, {
update: {
method: 'PUT',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
},
});
return api;
})
// controller
api.users
.update({where:{name:'kevin'}})
.$promise.then(function(success) {
// DO SOMETHING
});
...
api.issues.query().$promise.then(
function(success) {
// DO SOMETHING
});
controller.js
angular.module('app.main')
.controller('MainCtrl', function ($scope, currentUser, addAPI) {
$scope.form = {};
$scope.subdomain = currentUser.domainName;
$scope.add = function () {
addAPI.addAdmin(localStorage['token'], $scope.subdomain, $scope.form, onSuccess, onError);
};
take the details from the form and pass token and subdomain(took from current userDatService)
addAPI.js
angular.module('app.main').factory('addAPI', function ($resource, $http, Constant) {
var adminAPI = function () {
this.addAdmin = function (token, domain, dataObj, sucCall, errCall) {
$http({
method: 'POST',
url: Constant.API.prefix + domain + Constant.API.postfix + '/client/admin',
headers: {
'Token': token
},
data: dataObj
}).then(handleResp).catch(handleResp);
};
return new adminAPI;});
sending data to API URL
constants.js
angular.module('app.constants', [])
.constant('Constant', {
'API': {
prefix: 'http://api.',
postfix:'.dev.education.in/v1/academy-api/api/v.1.0'
}
});
1.I want to have a function in constants.js which accepts user or subdomain and returns URL?
2.is it the right way to format a base_url or any suggestions on improving.
3.I need to define a perfect base_url with prefix + domain + postfix + ...
I'm new to angularJs and Javascript and i tried my best to get a solution but functions are not working with constants
It may be a better method to put your constants in a vanilla javascript file and load them onto the stack (via html) before any angular-related scripts are loaded. That way they will already be in the global namespace and you can simply refer to them anywhere.
e.g.
Constant.js
var API = {
prefix: 'http://api.',
postfix:'.dev.education.in/v1/academy-api/api/v.1.0'
}
index.html
<script src="Constant.js"></script>
<script src="factories/addAPI.js"></script>
addAPI.js
angular.module('app.main').factory('addAPI', function ($resource, $http, Constant) {
var adminAPI = function () {
this.addAdmin = function (token, domain, dataObj, sucCall, errCall) {
$http({
method: 'POST',
url: API.prefix + domain + API.postfix + '/client/admin',
headers: {
'Token': token
},
data: dataObj
}).then(handleResp).catch(handleResp);
};
return new adminAPI;});
I'm new to AngularJS and
I needed to know if we can make a jQuery like Ajax call in Angular and wanted to know it's complete syntax,
if anyone could help me making the whole code syntax.
Example in jQuery I could do something like -
$.ajax(
{
url: 'someURL',
type: 'POST',
async: false,
data:
{
something: something,
somethingelse: somethingelse
},
beforeSend: function()
{
$('#someID').addClass('spinner');
},
success: function(response)
{
$('#someID').removeClass('spinner');
console.log(response);
},
complete: function(response)
{
$('#someID').removeClass('spinner');
console.log(response);
},
error: function (errorResp)
{
console.log(errorResp);
}
});
Now here's what I found out on making http call in Angular,
Need help in building the complete syntax, with all possible options -
var req = {
method: 'POST',
url: 'someURL',
headers: {
'Content-Type': undefined
},
data: {
//goes in the Payload, if I'm not wrong
something: 'something'
},
params:{
//goes as Query Params
something: 'something',
somethingElse: 'somethingElse'
}
}
$http(req)
.then(function()
{
//success function
},
function()
{
//Error function
});
now what if I want to attach a spinner on some id in the BeforeSend function like in jQuery and remove the spinner in success,
What is the Angular's way as a like to like for BeforeSend or making the http call async?
Angular even let you control this better :). Two ways can be chosen here:
1. Wrapping $http
You can write for each request with by using a wrapper of $http which will add some methods before and after you made request
app.factory('httpService',function($http){
function beginRequest() {};
function afterRequest() {};
return {
makeRequest: function(requestConfig){
beginRequest();
return $http(requestConfig).then(function(result){
afterRequest(result);
});
}
}
})
Then each time you can call this function to make a request. This is not new.
2. Using interceptor
Angular has a better way to handle for all request. It use a new concept named 'interceptor'. You write your interceptor as a normal service and push one or many interceptors into $http service and depend on type of interceptor, it will be called each time your request happen. Look at this picture to think about interceptor:
Some common task for interceptor can be: Add/remove a loading icon, add some more decorator to your http config such as token key, validate request, validate responded data, recover some request...
Here is example of a interceptor that add a token key into headers of a request
app.service('APIInterceptor', function($rootScope, UserService) {
var service = this;
service.request = function(config) {
var currentUser = UserService.getCurrentUser(),
access_token = currentUser ? currentUser.access_token : null;
if (access_token) {
config.headers.authorization = access_token;
}
return config;
};
service.responseError = function(response) {
return response;
};
})
Then add interceptor to your $http:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('APIInterceptor');
}]);
Now all request will be added a token key to header. cool right?
See here for more information:
there is eveyrthing here to help with your question :https://docs.angularjs.org/api/ng/service/$q http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/
$http functions are async by default.
And regarding the beforesend function, you could wrap the http call in a function and add the spinner just before making the call and remove it in the success call back. Something like this,
var makeHttpRequest = function(){
$('#someID').addClass('spinner');
$http(req).then(function(){
$('#someID').removeClass('spinner');
//rest processing for success callback
},function(){
$('#someID').removeClass('spinner');
//Error callback
});
}
The way I have implemented complex get and post in my angular application is as below:
Create a CRUDService as below:
yourApp.service('CRUDService', function ($q, $http) {
this.post = function (value, uri) {
var request = $http({
method: "post",
url: uri,
data: value
});
return request;
}
this.get = function (uri) {
var request = $http({
method: "get",
url: uri
});
return request;
}
});
As you can see this service simply returns a get/post object. Somewhere in my controller I use this service as below:
$('#exampleButton').button("loading"); //set the element in loading/spinning state here
var getObj = CRUDService.get("/api/get/something");
getObj.then(function(data){
//do something
$('#exampleButton').button("reset"); //reset element here
}, function(err){
//handle error
$('#exampleButton').button("loading"); //reset element here
});
$('#exampleButton').button("loading"); //set the element in loading/spinning state here
var postObj = CRUDService.post(postData,"/api/get/something");
postObj.then(function(data){
//do something
$('#exampleButton').button("reset"); //reset element here
}, function(err){
//handle error
$('#exampleButton').button("loading"); //reset element here
});
I hope this helps :)
The http call is async - it returns a promise that you can then handle with the try() and catch() methods. You can simply wrap your calls i.e.
function makeRequest() {
$scope.showSpinner = true;
$http
.get('http://www.example.com')
.then(function (response) {
$scope.showSpinner = false;
})
.catch(function (err) {
$scope.showSpinner = false;
});
}
If you would however like you use familiar syntax akin to jQuery then you can push your own custom interceptors. This will allow you intercept the requests and response and do whatever you want. In the below example we call functions if they are defined.
angular
.module('app', [])
.config(appConfig)
.factory('HttpInterceptors', httpInterceptors)
.controller('MyController', myController);
// app config
appConfig.$inject = ['$httpProvider'];
function appConfig($httpProvider) {
// add out interceptors to the http provider
$httpProvider.interceptors.push('HttpInterceptors');
}
// http interceptor definition
function httpInterceptors() {
return {
request: function(request) {
if (angular.isFunction(request.beforeSend)) {
request.beforeSend();
}
return request;
},
response: function(response) {
if (angular.isFunction(response.config.onComplete)) {
response.config.onComplete();
}
return response;
}
}
}
// controlller
myController.$inject = ['$scope', '$http', '$timeout'];
function myController($scope, $http, $timeout) {
$scope.showSpinner = false;
$http({
method: 'GET',
url: 'https://raw.githubusercontent.com/dart-lang/test/master/LICENSE',
beforeSend: function() {
$scope.showSpinner = true;
},
onComplete: function() {
$timeout(function() {
console.log('done');
$scope.showSpinner = false;
}, 1000);
}})
.then(function(response) {
console.log('success');
})
.catch(function(err) {
console.error('fail');
});
}
.spinner {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app='app' ng-controller='MyController'>
<div ng-class='{spinner: showSpinner}'>
Hello World!
</div>
</div>
I have a controller defined in my module as follows,
myTestApp.controller("LoginController", function($scope,$http,$location) {
$scope.submitForm = function(){
var userEmail = $scope.user.email;
var userPassword = $scope.user.password;
$http({
url:'api/login/',
headers: {'Content-Type': 'application/json'},
method:'POST',
data:{
username:userEmail,
password:userPassword
}})
.success(function(data){
$scope.loginResult = data;
});
};
});
I am trying to write a test case for mocking the HTTP call using httpBackend.
Here is my jasmine test code:
describe('make HTTP mock call', function() {
var scope, httpBackend, http, controller;
beforeEach(module('myTestApp'));
describe('with httpBackend', function() {
beforeEach(inject(function ($rootScope, $controller, $httpBackend, $http) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
http = $http;
controller = $controller('LoginController', {$scope : scope} );
httpBackend.when("POST", "api/login/",{'username':'test#gmail.com', 'password':'test'}, function(headers) {
return {
'Content-Type': 'application/json',
};
}).respond(200);
}));
afterEach(inject(function ($httpBackend){
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
}));
it('to check if user is valid', inject(function ($http) {
var expectedResponse = { success: true };
httpBackend.expectPOST('api/login/', {
"username": "test#gmail.com",
"password": "test"
}, function(headers){
return headers['Content-Type'] === 'application/json';
}).respond(function(method, url, data, headers, params){
return [200, {}, {}];
});
//actual HTTP call
$http({
url:'api/login/',
headers: {'Content-Type': 'application/json'},
method:'POST',
data:{
username:"test#gmail.com",
password:"test"
}});
//flush response
httpBackend.flush();
expect(scope.loginResult).toEqual(expectedResponse);
}));
});
});
However, when I run the test case, I get the below error
Expected undefined to equal Object({ success: true }).
I want to compare the response data from my HTTP call to the expectedResponse and if both are equal the test should pass.
However, I am not able to access the $scope variable loginResult from within my test case. can anyone tell me what I am doing wrong over here?
can someone describe the best way to mock the HTTP calls using Jasmine?
Your login data will actually be populated only when function submitForm will be called. So in the test, call the function before doing the flush() .
Update:
Make sure you have defined the
$scope.user={email :'test#gmail.com,password:'test'}
at the first line of your test (just after it('to check if user is valid', inject(function ($http) {)
I have a factory where I have a function getExpenseList which does an ajax call which queries the expense table and gives me the result.
Now I have two routes, 1 which is listing of expenses which is pushing the expense through the above function and the second route is an add. When I do a route change and come back to the listing page, the ajax call is made again. Ideally I should be able to store the expense object on the first ajax call and then reference the same object till someone is manually refreshing the browser.
please help me on this. Here is my factory code. Ideally I would like to refer to this.expenses if the data is present.
admin.factory('expenseFact', ['$http', function($http) {
var expense = {};
this.expenses = "";
expense.getExpenseList = function() {
this.expenses = $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "GET",
url: base_url + "rest/expenses"
});
return this.expenses;
};
return expense;
}]);
And here is my controller code
admin.controller('expenseLandCtrl', function ($scope,$rootScope,expenseFact) {
$scope.pageTitle = $rootScope.pageTitle;
expenseFact.getExpenseList().then(function (data) {
$scope.expenses = data.data;
});
});
admin.controller('expenseAddCtrl', function ($scope,$rootScope,expenseFact) {
$scope.pageTitle = $rootScope.pageTitle;
});
your factory will be like this
admin.factory('expenseFact', ['$http', function($http) {
return {
getExpenseList: function() {
var expense = {};
this.expenses = $http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "GET",
url: base_url + "rest/expenses"
});
return this.expenses;
}
}
}]);
and you can call it from controller same way and it wont call it automatically.
btw i recommend use of promises.
below is same code with use of promise
admin.factory('expenseFact', ['$http', '$q'. function($http, $q) {
return {
getExpenseList: function(){
var deferred = $q.defer();
$http({method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).
then(function(response) {
deferred.resolve(response.data);
}, function(response) {
deferred.reject(response.status)
});
return deferred.promise;
}
}
}]);
You need to get the expenses once when the factory is loaded for the first time;
admin.factory('expenseFact', ['$http', function($http) {
var expenses = null;
$http({
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "GET",
url: base_url + "rest/expenses"
}).success(function (exp) {
expenses = exp;
}); // get the expenses when the factory is loaded
return {expenses: expenses};
}]);
What this does is that it makes the expenses return from the factory refer to the one-time ajax call to get the expenses.