$resource service and controller - angularjs

I have a code like this:
angular.module( 'APPLICATION', ['ngResource'] )
.service( 'Service', ['$resource', function ($resource) {
var Model = $resource(
'/:node/:key.json',
{ node: '#node', key: '#key' },
{
query: {method: 'GET', isArray: false}
}
);
var responseMessage, responseData;
var successHandler = function (resource) {
responseMessage = { success: resource.result.message };
responseData = resource.result.data;
};
var errorHandler = function (resource) {
responseMessage = { error: resource.headers().message };
};
this.model = null;
this.fetch1 = function () {
var result = Model.query( {node: this.model.node} );
return result;
};
this.fetch2 = function () {
var result = Model.query( {node: this.model.node} );
result.$promise.then( successHandler, errorHandler );
return responseData;
};
}] )
.controller( 'Controller', ['$scope', 'Service', function ($scope, Service) {
Service.model = $scope.model;
// works
var response = Service.fetch1();
response.$promise.then( function (response) {
$scope.items = response.result.data;
} );
// doesn't work
$scope.items = Service.fetch2();
}] );
How can I make Service.fetch2 work?
I want to process data inside of the Service, not in the Controller, but I can't figure out how to send the data to the Controller once it's processed...

Since your fetch2 call also is async in nature you cannot do a direct assignment, as the results may not be available at that time. Return a promise from fetch2 as well. Like this
this.fetch2 = function () {
var result = Model.query( {node: this.model.node} );
return result.$promise.then( successHandler, errorHandler );
};
var successHandler = function (resource) {
responseMessage = { success: resource.result.message };
responseData = resource.result.data;
return responseData;
};
var errorHandler = function (resource) {
responseMessage = { error: resource.headers().message };
return responseMessage;
};
In your controller
Service.fetch2().then(function(data) {
$scope.items=data;
});

Related

How to cache response for Ajax 'POST' Request in AngularJS

I want to cache response from "POST" request in angularJS.
In Ajax, "cache = true" works only for GET request. How can we achieve it using cacheFactory or any other method.
Here below I want to cache 'viewDetails' data for particular id and not call ajax(in turn backend) again and again on click.
Also, How do I bust the cache everytime(cachefactory), is it only for particular session and release cache itself once session is closed or need to bust it explicitly.
Any help is appreciated.
service.js.
import {moduleName} from "../config/constants";
const serviceName = `${moduleName}_dataService`;
angular.module(moduleName).factory(serviceName, service);
service.$inject = ['$q', '$http'];
function service($q, $http) {
return {
getDetailsData: getDetailsData
};
function getDetailsData(payload) {
const def = $q.defer();
const promise = $http({
method: 'POST',
url: '/order/gentrular-db/viewDetails',
data: payload
});
promise.then(
(response) => {
if (typeof response.data === 'undefined' || response.data === null) {
def.reject("Empty response body");
return;
}
def.resolve(response.data);
},
(error) => {
def.reject(error.status);
});
return def.promise;
}
}
export {serviceName};
controller.js:
import {serviceName as dataServiceName} from "../../services/detailsDataService";
controller.$inject = ['$scope', dataServiceName];
function controller($scope, dataService) {
const $ctrl = this;
// Input binding
$ctrl.productId = null;
$ctrl.onClickClose = null;
// Local binding
$ctrl.$onInit = onInit;
$ctrl.ready = false;
$ctrl.productDetailSection = null;
$ctrl.clinicalSection = null;
$ctrl.importantInformationSection = null;
$ctrl.close = close;
function onInit() {
const promise = dataService.getDetailsData(buildPayload());
promise.then((data) => {
$ctrl.productDetailSection = data.productDetailSection;
$ctrl.clinicalSection = data.clinicalSection;
$ctrl.importantInformationSection = data.impInformationSec;
$ctrl.ready = true;
});
}
function buildPayload() {
return {
productType: "hortiz",
productId: $ctrl.productId
};
}
function close() {
if (angular.isFunction($ctrl.onClickClose)) {
$ctrl.onClickClose();
}
}
}
export {controller};
I was able to cache response using cacheFactory. Here is my working code.
import {moduleName} from "../config/constants";
const serviceName = `${moduleName}_dataService`;
angular.module(moduleName).factory(serviceName, service);
service.$inject = ['$q', '$http', '$cacheFactory'];
function service($q, $http, $cacheFactory) {
return {
getDetailsData: getDetailsData
};
function getDetailsData(payload,productId) {
var cache = $cacheFactory.get('detailsDataCache') || $cacheFactory('detailsDataCache');
var cacheId = productId;
var cachedData = cache.get(cacheId);
const def = $q.defer();
if (!cachedData) {
const promise = $http({
method: 'POST',
url: '/order/gentrular-db/viewDetails',
data: payload
});
promise.then(
(response) => {
if (typeof response.data === 'undefined' || response.data === null) {
def.reject("Empty response body");
return;
}
cache.put(cacheId, response.data);
def.resolve(response.data);
},
(error) => {
def.reject(error.status);
});
}else {
return $q.when(cachedData);
}
return def.promise;
}
}
export {serviceName};

Update in service not reflecting in controller. AngularJS

I've ProductService and ProductsController. ProductService have ProductService.Products = []; variable which contains all the Products information.
I access this Products-information in ProductsController and stores in variable named $scope.Products = [];.
Problem is some other service also using "ProductService", and updating "Products Info", using "UpdateInfo" function exposed in ProductService. Now these changes are not getting reflected in ProductsController variable $scope.Products = [];.
This is my code.
sampleApp.factory('ProductService', ['$http', '$q', function ($http, $q){
var req = {
method: 'POST',
url: 'ProductData.txt',
//url: 'http://localhost/cgi-bin/superCategory.pl',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }//,
//data: { action: 'GET' }
};
var ProductService = {};
ProductService.Products = [];
return {
GetProducts: function () {
var defer = $q.defer();
$http(req).then(function(response) {
ProductService.Products = response.data;
defer.resolve(ProductService.Products);
}, function(error) {
defer.reject("Some error");
});
return defer.promise;
},
UpdateInfo: function (ProductID, VariantID) {
for (i in ProductService.Products) {
if (ProductService.Products[i].ProductID == ProductID) {
for (j in ProductService.Products[i].Variants) {
if (ProductService.Products[i].Variants[j].VariantID == VariantID) {
ProductService.Products[i].Variants[j].InCart = 1; /* Updating Info Here, But its not reflecting */
break;
}
}
break;
}
}
}
};
}]);
sampleApp.controller('ProductsController', function ($scope, $routeParams, ProductService, ShoppingCartService) {
$scope.Products = [];
$scope.GetProducts = function() {
ProductService.GetProducts().then
(
function(response) {
$scope.Products = response;
},
function(error) {
alert ('error worng');
}
);
};
$scope.GetProducts();
});
Can some one help me how to solve this issue?
You can create a $watch on ProductService.Products in your controller. When the value changes, you can update $scope.Products with the new value.
$scope.$watch('ProductService.Products', function() {
$scope.Products = ProductService.Products;
});
Try assigning ProductsService.Products to $scope.products.
$scope.GetProducts = function() {
ProductService.GetProducts().then
(
function(response) {
$scope.Products = ProductService.Products;
},
function(error) {
alert ('error worng');
}
);
};

$scope is not updated after database trigger

I have following controller which is posting a new user and also getting new users.
The problem here is after adding a new user, the scope is not updated so view is not affected. I have also tired returning the function so it expects a promise but didnt update the scope.
myapp.controllers('users', ['usersService', ''$scope',', function(usersService, $scope){
getUsers();
function getUsers(params) {
if (typeof(params) === "undefined") {
params = {page: 1};
}
usersService.getUsers(params).then(function (res) {
$scope.users = res.items;
$scope.usersListTotalItems = res._meta.totalCount;
$scope.usersListCurrentPage = res._meta.currentPage + 1;
});
}
}
$scope.addUser = function (user) {
usersService.adddNewUser(user).then(function (response) {
getUsers();
});
}
}]);
myApp.factory('userService', ['Restangular', '$http', function (Restangular, $http) {
return {
getUsers: function (params) {
var resource = 'users/';
var users = Restangular.all(resource);
return users.getList(params)
.then(function (response) {
return {
items : response.data[0].items,
_meta : response.data[0]._meta
}
});
},
adddNewUser: function (items) {
var resource = Restangular.all('users');
var data_encoded = $.param(items);
return resource.post(data_encoded, {}, {'Content-Type': 'application/x-www-form-urlencoded'}).
then(function (response) {
return response;
},
function (response) {
response.err = true;
return response;
});
}
};
}]);
I think it is a small error however you did not include $scope in the argument for the controller function.
myapp.controllers('users', ['usersService','$scope', function(usersService $scope){
getUsers();
function getUsers(params) {
if (typeof(params) === "undefined") {
params = {page: 1};
}
usersService.getUsers(params).then(function (res) {
$scope.users = res.items;
$scope.usersListTotalItems = res._meta.totalCount;
$scope.usersListCurrentPage = res._meta.currentPage + 1;
});
}
}
$scope.addUser = function (user) {
usersService.adddNewUser(user).then(function (response) {
getUsers();
});
}
}]);

Storing tokens with OAuth 2.0 in Angular

I have an app which displays Google Calendar data, but it requires an initial login. I know it's possible to store tokens using OAuth 2.0, but I'm not sure how to go about doing it. Here is my code below. I'd like for the webpage to display the a calendar using JSON data from a google calendar without login.
Controller
angular.module('demo', ["googleApi"])
.config(function(googleLoginProvider) {
googleLoginProvider.configure({
clientId: '239511214798.apps.googleusercontent.com',
scopes: ["https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/plus.login"]
});
})
.controller('DemoCtrl', ['$scope', 'googleLogin', 'googleCalendar', 'googlePlus', function ($scope, googleLogin, googleCalendar, googlePlus) {
$scope.login = function () {
googleLogin.login();
};
$scope.$on("googlePlus:loaded", function() {
googlePlus.getCurrentUser().then(function(user) {
$scope.currentUser = user;
});
})
$scope.currentUser = googleLogin.currentUser;
$scope.loadEvents = function() {
this.calendarItems = googleCalendar.listEvents({calendarId: this.selectedCalendar.id});
}
$scope.loadCalendars = function() {
$scope.calendars = googleCalendar.listCalendars();
}
}]);
googleAPi
angular.module('googleApi', [])
.value('version', '0.1')
.service("googleApiBuilder", function($q) {
this.loadClientCallbacks = [];
this.build = function(requestBuilder, responseTransformer) {
return function(args) {
var deferred = $q.defer();
var response;
request = requestBuilder(args);
request.execute(function(resp, raw) {
if(resp.error) {
deferred.reject(resp.error);
} else {
response = responseTransformer ? responseTransformer(resp) : resp;
deferred.resolve(response);
}
});
return deferred.promise;
}
};
this.afterClientLoaded = function(callback) {
this.loadClientCallbacks.push(callback);
};
this.runClientLoadedCallbacks = function() {
for(var i=0; i < this.loadClientCallbacks.length; i++) {
this.loadClientCallbacks[i]();
}
};
})
.provider('googleLogin', function() {
this.configure = function(conf) {
this.config = conf;
};
this.$get = function ($q, googleApiBuilder, $rootScope) {
var config = this.config;
var deferred = $q.defer();
return {
login: function () {
gapi.auth.authorize({ client_id: config.clientId, scope: config.scopes, immediate: false}, this.handleAuthResult);
return deferred.promise;
},
handleClientLoad: function () {
gapi.auth.init(function () { });
window.setTimeout(checkAuth, 1);
},
checkAuth: function() {
gapi.auth.authorize({ client_id: config.clientId, scope: config.scopes, immediate: true }, this.handleAuthResult );
},
handleAuthResult: function(authResult) {
if (authResult && !authResult.error) {
var data = {};
$rootScope.$broadcast("google:authenticated", authResult);
googleApiBuilder.runClientLoadedCallbacks();
deferred.resolve(data);
} else {
deferred.reject(authResult.error);
}
},
}
};
})
.service("googleCalendar", function(googleApiBuilder, $rootScope) {
var self = this;
var itemExtractor = function(resp) { return resp.items; };
googleApiBuilder.afterClientLoaded(function() {
gapi.client.load('calendar', 'v3', function() {
self.listEvents = googleApiBuilder.build(gapi.client.calendar.events.list, itemExtractor);
self.listCalendars = googleApiBuilder.build(gapi.client.calendar.calendarList.list, itemExtractor);
self.createEvent = googleApiBuilder.build(gapi.client.calendar.events.insert);
$rootScope.$broadcast("googleCalendar:loaded")
});
});
})
.service("googlePlus", function(googleApiBuilder, $rootScope) {
var self = this;
var itemExtractor = function(resp) { return resp.items; };
googleApiBuilder.afterClientLoaded(function() {
gapi.client.load('plus', 'v1', function() {
self.getPeople = googleApiBuilder.build(gapi.client.plus.people.get);
self.getCurrentUser = function() {
return self.getPeople({userId: "me"});
}
$rootScope.$broadcast("googlePlus:loaded")
});
});
})
What you will want to do is after the result comes back you will want to save it off to localStorage or a cookie and then use that in the future if it exists.
Essentially you will need to update your handleAuthResult to store the result from the Google API:
handleAuthResult: function (authResult) {
if (authResult && !authResult.error) {
var data = {};
$rootScope.$broadcast("google:authenticated", authResult);
googleApiBuilder.runClientLoadedCallbacks();
// here you will store the auth_token
window.localStorage.setItem('auth_token', authResult.token /*I don't know what this response looks like, but it should be similar to this*/ );
deferred.resolve(data);
} else {
deferred.reject(authResult.error);
}
},
Live Demo

Angular promise in async loop function

I have an upload function which loops through the selected files and adds them on the servers file system.
Upload factory
app.factory('uploadFactory', function ($upload, $q) {
var uploadFactory = {};
var image = {
Models: [],
Images: [],
uploadImages: function () {
var defer = $q.defer();
for (var i = 0; i < this.Models.length; i++) {
var $file = this.Models[i].file;
(function (index) {
$upload
.upload({
url: "/api/upload/",
method: "POST",
file: $file
})
.success(function (data, result) {
// Add returned file data to model
var imageObject = {
Path: data.Path,
Description: image.Models[index].Description,
Photographer: image.Models[index].Photographer
};
image.Images.push(imageObject);
defer.resolve(result);
});
})(i);
}
return defer.promise;
}
};
uploadFactory.image = function () {
return image;
};
return uploadFactory;
});
In my controller
$scope.imageUpload = new uploadFactory.image;
$scope.create = function () {
var uploadImages = $scope.imageUpload.uploadImages();
uploadImages.then(function ()
$scope.ship.Images = $scope.imageUpload.Images;
shipFactory.create($scope.ship).success(successPostCallback).error(errorCallback);
});
};
My problem is that the promise only holds the promise for the first upload through the looping. I have read something about $q.all() but I'm not sure how to implement it to work.
How can I make it to hold through the whole loop? Thanks!
Solution
var image = {
Models: [],
Images: [],
uploadImages: function () {
for (var i = 0; i < this.Models.length; i++) {
var $file = this.Models[i].file;
var defer = $q.defer();
(function (index) {
var promise = $upload
.upload({
url: "/api/upload/",
method: "POST",
file: $file
})
.success(function (data, result) {
// Add returned file data to model
var imageObject = {
Path: data.Path,
Description: image.Models[index].Description,
Photographer: image.Models[index].Photographer
};
image.Images.push(imageObject);
defer.resolve(result);
});
promises.push(promise);
})(i);
}
return $q.all(promises);
}
};
You're right $q.all() is the way to go here (totally untested -- but i think this is at least the right direction..):
app.factory('uploadFactory', function ($upload, $q) {
var uploadFactory = {};
var image = {
Models: [],
Images: [],
uploadImages: function () {
var promises = [];
for (var i = 0; i < this.Models.length; i++) {
var $file = this.Models[i].file;
var response = $upload
.upload({
url: "/api/upload/",
method: "POST",
file: $file
})
.success(function (data, result) {
// Add returned file data to model
var imageObject = {
Path: data.Path,
Description: $file.Description,
Photographer: $file.Photographer
};
image.Images.push(imageObject);
});
promises.push(response);
}
return $q.all(promises);
}
};
uploadFactory.image = function () {
return image;
};
return uploadFactory;
});

Resources