Data object variable in angular service to update via ajax call - javascript

Use Case:
I want to create a service in angular which will return me a data object which is a variable inside service, which gets updated once via ajax call.
For first time till data is not received via ajax, it will return {}. Once data is received it will return that data always.
Issue:
The data is properly received in ajax. The structure of data received is an object. I have checked it by logging in console. But next time when this service is called it is again calling ajax as variable inside service is not getting updated.
Can anyone suggest why is this happening and what would be the idle way to achieve above ?
Code:
angular.module('myapp', []).service('TagService', function ($http, CONSTANTS) {
this.tagsData = {};
this.getTagsData = function (cacheMode) {
if (JSON.stringify(this.tagsData) != "{}") {
console.log("returning from cache");
return this.tagsData;
}
$http({
method: 'GET',
url: CONSTANTS['base_url_s'] + 'api/v1/get_all_tags_data/',
params: {'params': JSON.stringify({})}
}).success(
function (data, status, headers, config) {
if (data && data["success"] && data["success"] == true) {
this.tagsData = data["data"];
}
return this.tagsData;
}).error(
function (data, status, headers, config) {
return {};
});
};
});

You should not use this in your function. The this keyword is function scoped. You're not updating the same variable in your callback and in your first condition.
angular.module('myapp', []).service('TagService', function ($http, CONSTANTS) {
var tagsData = {};
this.getTagsData = function (cacheMode) {
if (JSON.stringify(tagsData) != "{}") {
console.log("returning from cache");
return tagsData;
}
$http({
method: 'GET',
url: CONSTANTS['base_url_s'] + 'api/v1/get_all_tags_data/',
params: {'params': JSON.stringify({})}
}).success(
function (data, status, headers, config) {
if (data && data["success"] && data["success"] == true) {
tagsData = data["data"];
}
return tagsData;
}).error(
function (data, status, headers, config) {
return {};
});
};
});
One more thing, you must use promise rather than returning your datas. Check the documentation about $q here.
The right way should be :
angular.module('myapp', []).service('TagService', function ($http, CONSTANTS, $q) {
var tagsData = {};
this.getTagsData = function (cacheMode) {
var defer = $q.defer();
if (JSON.stringify(tagsData) != "{}") {
console.log("returning from cache");
defer.resolve(tagsData);
}else{
$http({
method: 'GET',
url: CONSTANTS['base_url_s'] + 'api/v1/get_all_tags_data/',
params: {'params': JSON.stringify({})}
}).success(
function (data, status, headers, config) {
if (data && data["success"] && data["success"] == true) {
tagsData = data["data"];
}
return defer.resolve(tagsData);
}).error(
function (data, status, headers, config) {
return defer.reject({});
});
};
}
return defer.promise;
});
And then you should call:
TagService.getTagsData().then(function(yourTags){
// yourTags contains your data
});

Related

Loader not being shown on ajax request in angular js

Since I am using ajax request using $http. It takes a long time since my operation on server takes time. I need to show loader while processing request, but the loader does not show. Although my code seems correct. I tried different methods but did not work.
Index.html
<body ng-app="app">
<!-- loader, can be used on multiple pages-->
<div class="loading loader-quart" ng-show="isLoading"></div>
<!-- my logic -->
</body>
addCtrl.js
//method to get all the attributes and send to server using service
$scope.add = function () {
if ($scope.Option == 'newInstance')
$scope.singleObject.FK_Name = 'MetisEmptyTemplate';
$rootScope.isLoading = true;
var featuresList = websiteService.getUpdatedTree($scope.treeDataSource);
var formData = new Website("", $scope.singleObject.Name, $scope.singleObject.DisplayName, $scope.singleObject.Description, $scope.singleObject.State, "", $scope.singleObject.FK_Name, $scope.singleObject.Email, featuresList);
websiteService.addwebsite(formData);
$rootScope.isLoading = false;
}
websiteService.js
//service to add website
this.addwebsite = function (website) {
$http({
method: 'POST',
url: $rootScope.url + 'Add',
data: JSON.stringify(website),
contentType: 'application/json'
}).success(function (data) {
alert(data);
}).error(function (data, status, headers, config) {
//alert(data);
});
}
Since I am going to turn isLoading as "true" in start and then after request completes I turn isLoading "false". Where is the problem in code?
Your websiteServices code gets executed asynchronously. Which means that the above code would display the loader and then pretty much hide it again instantly.
To handle async code in the controller you must return a promise from the service and put the hiding of the spinner in a callback function using .then().
service:
this.addwebsite = function (website) {
var deferred = $q.defer();
$http({
method: 'POST',
url: $rootScope.url + 'Add',
data: JSON.stringify(website),
contentType: 'application/json'
}).success(function (data) {
alert(data);
deferred.resolve(data);
}).error(function (data, status, headers, config) {
//alert(data);
deferred.reject(data);
});
return deferred.promise
}
controller:
websiteService.addwebsite(formData).then(function(){
$rootScope.isLoading = false
});
this.insertMliveResponse = function(data){
var defer=$q.defer();
var requestURL='/mlive-portlet/rest/mliveResponseService/insertmLiveResponse';
httpRequest(requestURL,data).then(function(data){
defer.resolve(data.data);
},function(data){
defer.reject(data.data);
})
return defer.promise;
}
If you are making request then,
I think the best way to show hide loader is interceptor
In my snippet, I am using loader service to activate/deactivate loader
For Eg:
// http.config.js file
export function httpConfig($httpProvider, AuthInterceptProvider) {
'ngInject';
AuthInterceptProvider.interceptAuth(true);
// added for show loader
$httpProvider.interceptors.push(function (loaderService, $q) {
'ngInject';
return {
'request': function (config) {
loaderService.switchLoaderModeOn();
return config;
},
'requestError': function (rejection) {
loaderService.switchLoaderModeOff();
return $q.reject(rejection);
},
'response': function (response) {
loaderService.switchLoaderModeOff();
return response;
},
'responseError': function (rejection) {
loaderService.switchLoaderModeOff();
return $q.reject(rejection);
}
};
});
}
// and in your module.js file
import {httpConfig} from './config/http.config';
.config(httpConfig)

AngularJS Factory Service not returning dynamic data to controller

This is my factory service and it is fetching data from a web service
var customersFactory = function ($http) {
var customer = [];
var getCustomersURL = "http://localhost:50340/Services/CustomerService.asmx/GetCustomers";
customer.XMLtoJSON = function (data) {
data = data.replace('<?xml version="1.0" encoding="utf-8"?>', ''); ;
data = data.replace('<string xmlns="http://tempuri.org/">', '').replace('</string>', '');
return $.parseJSON(data);
};
customer.GetCustomers = function () {
$http.post(getCustomersURL).success(function (data, status, headers, config) {
return customer.XMLtoJSON(data);
}).error(function (ata, status, headers, config) { });
};
return customer;
};
app.factory('customersFactory', customersFactory);
Now, this is being used in my controller
app.controller("CustomersController", function ($scope, customersFactory) {
var service = [];
service = customersFactory.GetCustomers();
$scope.Customers = service;
if ((typeof (service) != 'undefined') && service.length > 0) {
service.then(function (result) {
$scope.Customers = result;
});
}
});
The value of service is always undefined or empty. Data is not being passed from factory to controller. Im calling a simple web service, no fancy APIs or WCF.
It there was some static/dummy data, its working fine. The controller is fetching the data and is being displayed.
Where am I doing wrong?
Any help is greatly appreciated.
Thank you
change this line var customer = []; to this var customer = {};
Or better yet make it a class...
change this to return the promise:
customer.GetCustomers = function () {
return $http.post(getCustomersURL).error(function (data, status, headers, config) { });
};
and usage in the controller:
app.controller("CustomersController", function($scope, customersFactory) {
$scope.Customers = [];
customersFactory.getCustomers().success(function(data, status, headers, config) {
$scope.Customers = customersFactory.XMLtoJSON(data);
});
});

Why is $q undefined in the following angularjs example?

At the line var deferred = $q.defer();
When I try to submit a simple form using the following code, I get: TypeError: Unable to get property 'defer' of undefined or null reference.
angular.module('app').controller('enrollCtl', function enrollCtl($q, $http)
{
// Using 'Controller As' syntax, so we assign this to the vm variable (for viewmodel).
var vm = this;
// Bindable properties and functions are placed on vm.
vm.applicantData = {
FirstName: "",
Comment: ""
};
vm.registerApplicant = function submitForm($q, $http)
{
console.log('posting data::' + vm.applicantData.FirstName)
var serverBaseUrl = "https://test.com/TestForm";
var deferred = $q.defer();
return $http({
method: 'POST',
url: serverBaseUrl,
data: vm.applicantData
}).success(function (data, status, headers, cfg)
{
console.log(data);
deferred.resolve(data);
}).error(function (err, status)
{
console.log(err);
deferred.reject(status);
});
return deferred.promise;
};
})
You've declared $q and $http twice as parameters, once at your controller and once at your function. The modules will only get injected in your controller, and the parameters of your function (where they have the value undefined if you call the function with nothing) shadow them.
Notice that you should not use $q.deferred here anyway, just return the promise that $http already gives you:
vm.registerApplicant = function submitForm() {
console.log('posting data::' + vm.applicantData.FirstName)
return $http({
// ^^^^^^
method: 'POST',
url: "https://test.com/TestForm",
data: vm.applicantData
}).success(function (data, status, headers, cfg) {
console.log(data);
}).error(function (err, status) {
console.log(err);
});
};

How to set $http.error() in angular throughout all $http calls?

How would I go about setting a function for all .error calls from the $http service wherever used.
Throughout my app I have used many $http calls wrapped in a service and would like to avoid duplication of implementing all .error methods.
e.g.
postTest: function (data) {
var url = '/test';
return $http({
method: 'POST',
url: url,
data: data
}).
success(function (data) {
return data;
}).
error(function (status) { //Avoid duplication of this throughout all $http calls.
if (status === 404) {}
return status;
});
}
you could create and interceptor to catch all the errors
so something like this
var applicationWideInterceptors = function ($q, toastrSrvc) {
return {
responseError:function(rejection) {
//do something with the rejection
if (rejection.status === 404) {
toastrSrvc.error(rejection.data);
}
return $q.reject(rejection);
}
}
};
app.factory("appWideIntercpt", ["$q", "toastrSrvc", applicationWideInterceptors]);
dont forget to add it to your config block
$httpProvider.interceptors.push("appWideIntercpt"

Angularjs resource factory transformResponse is not called

Below is my code
MY_MODULE.factory("SOME_API", ['$resource', '$http', '$rootScope', function($resource, $http, $rootScope){
return $resource("/appi/get/", {responseFormat: 'json', responselanguage:'English', pageno:1}, {
search:{
method:'GET',
transformResponse: [function (data, headersGetter) {
console.log(data);
// you can examine the raw response in here
$log.info(data);
$log.info(headersGetter());
return {tada:"Check your console"};
}].concat($http.defaults.transformResponse),
params:{
param1:'SOME_DATA',
param2:'SOME_DATA2',
}
}
}
}
I m using angular 1.0.7, can't figure out why my transformResponse is not called. I believe this version of angular supports transformResponse, if not how to implement similar callback.
transformResponse is not a parameter to $resource. The response interceptor are configured on $httpProvider. See the documentation of $http (Section Response Interceptor).
Keep in mind that once configured these interceptors would run for each request that was made by $http.
Is it possible to use AngularJS 1.2?
I had the exact same problem with 1.0.8. After I changed to angular-1.2.0-rc.2, my resource's transformResponse callback started being called.
Below is the solution, basically a wrapper to $http, which emulates default resource
$rootScope.woiresource = function (url, defaults, actions) {
var $res = {};
for (var i in actions) {
var default_params = {};
for (var di in defaults) {
default_params[di] = defaults[di];
}
for (var ai in actions[i].params) {
default_params[ai] = actions[i].params[ai];
}
$res[i] = (function (url, method, default_params) {
return function (params, callback, headers) {
if (typeof params == 'function') {
callback = params;
params = {};
}
if (typeof headers == 'undefined') {
headers = {};
}
for (var pi in params) {
default_params[pi] = params[pi];
}
return $http({
url: url,
method: method,
transformResponse: [function (strData, headersGetter) {
//Do Something
}].concat($http.defaults.transformResponse),
params: default_params,
headers: headers,
}).success(function (data) {
callback(data);
});
};
})(url, actions[i].method, default_params);
}
return $res;
};
Parameters are similar to default resource just changed the working, hope this helps some people.

Categories

Resources