passing data between controllers when https are successful - javascript

I am trying to pass the data between controllers when each http request is successful. that said, here is a hierarchy
<div ng-controller="ParentCtrl as parent">
<div ng-controller="ChildOneCtrl as chi1"></div>
<div ng-controller="ChildTwoCtrl as chi2"></div>
<div ng-controller="ChildThreeCtrl as chi3"></div>
</div>
loading data within each next controller depends on previous one, namely when http request is successful.
ChildOneCtrl:
function ChildOneCtrl ($scope, sharedService) {
var chi1 = this;
sharedService.getChildOneData()
.then(function (res) {
$rootScope.$emit('childOneDataEmited', res.data);
}).catch(function (err) {
console.log(err);
});
}
ChildTwoCtrl:
function ChildTwoCtrl ($scope, $rootScope, sharedService) {
var chi2 = this;
var onEmitChildOne = $rootScope.$on('childOneDataEmited', function (event, data) {
getData(data);
});
$scope.$on('$destroy', onEmitChildOne);
function getData(data){
var chi1Data = data;
if(chi1Data.uEnabled){
sharedService.getChildTwoData()
.then(function (res) {
$rootScope.$emit('childTwoDataEmited', res.data);
}).catch(function (err) {
console.log(err);
});
}
}
}
ChildThreeCtrl:
function ChildThreeCtrl ($scope, $rootScope, sharedService) {
var chi3 = this;
var onEmitChildThree = $rootScope.$on('childTwoDataEmited', function (event, data) {
getData(data);
});
$scope.$on('$destroy', onEmitChildThree);
function getData(data){
var chi2Data = data;
sharedService.getChildThreeData()
.then(function (res) {
//to do some data manipulation
console.log(res)
console.log(chi2Data)
}).catch(function (err) {
console.log(err);
});
}
}
while this get the job done, the hierarchy is likely going to change, become deeper so I am wondering if there is a better way to do it so I dont overuse events ?

Why don't you share the data it self through the sharedService ?
After you get the data from first controller, just assign it to a shared variable in sharedService and in the child controller (second one) just set a watch for this shared variable. like this:
function ChildOneCtrl ($scope, sharedService) {
var chi1 = this;
sharedService.getChildOneData()
.then(function (res) {
sharedService.sharedData = res.Data;
}).catch(function (err) {
console.log(err);
});
}
function ChildTwoCtrl ($scope, $rootScope, sharedService) {
var chi2 = this;
$scope.watch('sharedService.sharedData', function(newValue) {
// do something like calling another endpoint using http.
});
}
I didn't try it, it may fail, but the idea is to share data throug service.
UPDATE
Another approach is to have two then() or more:
function sharedService($q, $http) {
var service = {
sharedData1Promise: { then: function() {} },
sharedData2Promise: { then: function() {} },
sharedData3Promise: { then: function() {} },
getSomeData1: getSomeData1
};
function getSomeData1() {
sharedData1Promise = $http.get( /* what ever is here */ );
return sharedData1Promise;
}
function getSomeData2() {
sharedData2Promise = $http.get( /* what ever is here */ );
return sharedData2Promise;
}
function getSomeData3() {
sharedData3Promise = $http.get( /* what ever is here */ );
return sharedData3Promise;
}
return service;
}
function ChildOneCtrl ($scope, sharedService) {
var chi1 = this;
sharedService.getSomeData1()
.then(function (res) {
/* do something */
}).catch(function (err) {
console.log(err);
});
}
function ChildTwoCtrl ($scope, sharedService) {
var chi2 = this;
sharedService.sharedData1Promise
.then(function (res) {
sharedService.getSomeData2();
/* do something with data coming from the first child calling getSomeData1 method */
}).catch(function (err) {
console.log(err);
});
}

Related

Issue with AngularJS promises within a factory

I have an angularjs factory like this:
'use strict';
angular.module('frontRplApp')
.factory('paymentService', function ($rootScope, $http, config, tools) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function () {
var args = {};
return $http.post(urlBase + 'api/investor/payment/create', args);
}
});
And I intend to use it inside a controller like this (the important issue is being to do something different if all went well or if there was an error)
$scope.order = function () {
console.log('PaymentCashCtrl.order');
$scope.disabledButtons.submitCashOrder = true;
paymentService.create()
.then(
function (response) {
// do something with response
}, function (error) {
// do something with an error
}));
};
However my issue is that Id like to update some of the paymentService fields as the response of the $http.post is resolved and then return the promise so that the function(response) and function(error) callbacks in the controller keep working.
I tried with something like:
return $http.post(urlBase + 'api/investor/payment/create', args)
.then(function(response){
console.log(response);
this.response = response;
return response;
});
But it doesnt work since the function(error) handler in the controller is never called.
I want to use my handlers in the controller but also make some updates when the $http.post response is resolved.
Thanks.
in the factory, you need to return the functions paymentService object. also, don't resolve the promise inside the factory. resolve it in the controller.
.factory('paymentService', function($rootScope, $http, config, tools) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function() {
var args = {};
return $http.post(urlBase + 'api/investor/payment/create', args);
}
}
return paymentService;
});
$scope.order = function() {
console.log('PaymentCashCtrl.order');
$scope.disabledButtons.submitCashOrder = true;
paymentService.create()
.then(
function(response) {
// do something with response
},
function(error) {
// do something with an error
}));
};
Use $q
Change your factory code to this:
angular.module('frontRplApp')
.factory('paymentService', function ($rootScope, $http, config, tools, $q) {
var urlBase = config.baseUrl;
var paymentService = {
response: {},
create: function () {
var deferred = $q.defer();
var args = {};
$http.post(urlBase + 'api/investor/payment/create', args)
.then(function(response){
console.log(response);
paymentService.response = response;
deferred.resolve(response);
}, function (error) {
deferred.reject(error);
});
return deferred.promise;
}
};
return paymentService;
});

How to store result from $http.get into a variable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I have the following scenario, I need data from a particular url.I also need to save this datas into a variable that I can call everywhere in my controller. To overcome such issue, I have written a service like below :
app.service("userData", function ($http, $q) {
var deferred = $q.defer();
this.getUsers = function () {
return $http.get('/users')
.then(function (response) {
deferred.resolve(response.data);
return deferred.promise;
}, function (response) {
deferred.reject(response);
return deferred.promise;
})
;
};
});
And then my controller looks like :
app.controller('UserCtrl', function($scope, $q, userData) {
var myData = userData.getUsers()
.then(
function (result) {
$scope.users = result;
},
function (error) {
console.log(error.statusText);
}
);
console.log(myData)
});
It prints :
So how can i store data into a variable which is accessible all over the controller ?
Thanks..
I suggest you something like that:
angular.module("app").factory("userService", userService);
userService.$inject = ["$http", "$q"];
function userService($http, $q) {
var deferred = $q.defer();
var promise = null;
var currentUser = null;
return {
getUserInfo: function () {
if (promise) {
deferred.resolve(currentUser);
return (currentUser) ? deferred.promise : promise;
}
else {
promise = $http.get("http://swapi.co/api/people/1/").then(function (response) {
return currentUser = response.data.name;
});
return promise;
}
}
}
}
you can call then any time userService.getUserInfo() to get the cached data.
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl',
controllerAs: 'vc'
});
}])
.controller('View1Ctrl', function (userService) {
var vm = this;
userService.getUserInfo().then(function (result) {
vm.name = result
}, function (err) {
vm.name = err
});
});
I create a git repository to test it out: https://github.com/leader80/angular-cache-service
I hope it helps

Angularjs, function not being properly invoked inside controller

I'm doing this login exercise where users can login and post notes, and view the notes that they've posted. My problem is when I logout and login with a different user I see the notes from the previous user.
Here's an illustration:
I log in with a different user then this shows up:
I restart the page and the appropriate note shows up:
The controller for this:
exports.homeController = function ($scope, $location, $q, $users, $window, $notes, $http) {
var auth = function () {
var userInfo = $users.getUserInfo()
if (userInfo) {
return $q.when(userInfo)
} else {
return $q.reject({ authenticated: false })
}
}
$scope.userInfo = auth()
myNotes($scope.userInfo.$$state.value.accessToken) // I invoke my function to get the notes for each specific user but it doesn't seem to work.
$scope.logout = function () {
$users.logout()
.then(function (results) {
$scope.userInfo = null
$scope.myNotes = null
$location.path('/')
}, function (err) {
console.log(err)
})
}
$scope.notes = {
notes: ''
}
$scope.postNote = function () {
$notes.postNotes($scope.userInfo.$$state.value.accessToken, $scope.notes)
.then(function (result) {
$scope.myNotes.push($scope.notes)
$scope.notes = ''
}, function (err) {
console.log(err)
})
}
function myNotes (user_id) {
$notes.getMyNotes(user_id)
.then(function (result) {
console.log(result)
$scope.myNotes = result.data
}, function (err) {
console.log(err)
})
}
}
This is the app https://login-sys.herokuapp.com/
I've found your non-minified code for the services.
Based on that I think the problem is that you declare var deferred = $q.defer() one time in the $notes service.
I think it should be "renewed" every time the service methods are called:
function getMyNotes (user_id) {
var deferred = $q.defer();
$http.get('/api/myNotes/' + user_id + '?access_token=' + user_id)
.then(function (result) {
deferred.resolve(result)
}, function (err) {
deferred.reject(err)
});
return deferred.promise
}
Similarly in postNotes.
The second time you return the same promise with the same value, so your homeController's getMyNotes function will get the same result despite the $notes service making a new request.
In the $users service's logout and signup functions you are already using it correctly.

Undefined when returning $http promise in controller from factory

No matter what I do I always get $$state or undefined back from my factory API call. I've tried promises and simply returning response.data from .then but nothing I tried works.
I can get the proper response data into my controller but then when I try to assign it to anything I just get undefined or $$state, depending on which method I use.
My factory:
factory('forecastFactory', function ($http, $q, SundialConfig) {
var Forecast = {};
var weatherKey = SundialConfig.openWeatherKey;
Forecast.dayCnt = 1;
Forecast.prepareCity = function (city) {
city === undefined ? city = 'Chicago, IL' : city = city;
return city;
}
Forecast.getForecast = function (city) {
var preparedCity = Forecast.prepareCity(city);
var deferred = $q.defer();
$http.jsonp('http://api.openweathermap.org/data/2.5/forecast/daily?', {
params: {
appid: weatherKey,
q: preparedCity,
cnt: Forecast.dayCnt,
callback: 'JSON_CALLBACK'
}
})
.then(function (res) {
console.log("success");
deferred.resolve(res);
})
.catch(function (err) {
console.log('error');
});
return deferred.promise;
}
return Forecast;
});
My controller:
controller('ForecastController', function ($scope, $location, forecastFactory, locationService) {
vm = this;
forecastFactory.getForecast('Chicago, IL').then(function (res) {
console.log(res);
vm.forecast = res;
});
});
I think you don't need to use $q because $http returns a promise,
you can do
Forecast.getForecast = function(city) {
var preparedCity = Forecast.prepareCity(city);
return $http.jsonp('http://api.openweathermap.org/data/2.5/forecast/daily?', {
params: {
appid: weatherKey,
q: preparedCity,
cnt: Forecast.dayCnt,
callback: 'JSON_CALLBACK'
}
})
.then(function(res) {
console.log("success");
return res.data;
})
.catch(function(err) {
console.log('error')
return []; // or {} depending upon required data
});
}
and in controller, do the same as you are doing now
Other way is simply return the promise returned by $http
Forecast.getForecast = function(city) {
var preparedCity = Forecast.prepareCity(city);
return $http.jsonp('http://api.openweathermap.org/data/2.5/forecast/daily?', {
params: {
appid: weatherKey,
q: preparedCity,
cnt: Forecast.dayCnt,
callback: 'JSON_CALLBACK'
}
})
}
and in controller do this
Sundial.Controllers.
controller('ForecastController', ['$scope', '$location', 'forecastFactory', 'locationService', function($scope, $location, forecastFactory, locationService) {
vm = this;
forecastFactory.getForecast('Chicago, IL').then(function(res) {
console.log(res)
vm.forecast = res.data;
}, function(err){
// do something
})
}]);

Angularjs mock a function that returns an $http promise

I have and angularjs app in which I have a controller that calls a service that returns an $http call. The app works fine, but I am trying to test the controller and running into issues.
My service:
myApp.factory("MyService", function ($http) {
var service = {};
service.save = function (item) {
return $http.post('../api/Save', item)
.success(function () {
console.log("Saved items on current page");
})
.error(function () {
console.log("Error saving items on page")
});
};
return service;
});
My controller:
myApp.controller("MyCtrl", function ($scope, MyService) {
$scope.save = function () {
MyService.save($scope.data)
.success(function () {
//do something
}).error(function () {
//do something else
});
};
});
The app works exactly as expected.
My spec file:
describe('MyCtrl', function () {
var myCtrl, mySvc, scope;
beforeEach(function () {
module('MyApp');
module(function ($provide) {
$provide.service('MyService', function () {
this.save = function () { };
});
});
inject(function ($injector) {
mySvc = $injector.get('MyService');
});
spyOn(mySvc, 'save').and.callFake(function () {
return {
success: function (callback) {
callback({ /* something */ });
},
error: function (callback) {
callback({/* something else */ });
}
};
});
inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
myCtrl = $controller('MyCtrl', { $scope: scope });
});
});
describe('when save button has been hit', function () {
it('should save', function () {
scope.save();
expect(mySvc.save).toHaveBeenCalled();
});
});
});
The test gives me an error that 'undefined' is not an object (near '...}).error(function () {...'). If I remove the '...}).error(function () {...') portion from the controller itself then the test works fine, but I don't want to get rid of that functionality.
Try using return callback()
spyOn(mySvc, 'save').and.callFake(function () {
return {
success: function (callback) {
return callback({ /* something */ });
},
error: function (callback) {
return callback({/* something else */ });
}
};
});
I got something working! The issue is that in my controller I am chaining the response behavior, which the mocked function doesn't know how to handle. The solution I found was to direct back to the function after each case.
$provide.service('MyService', function () {
this.save = function () {
return {
success: function (callback) {
callback();
return this;
},
error: function (callback) {
callback();
return this;
},
finally: function (callback) {
callback();
return this;
}
};
};
});
and then change the spy to just:
spyOn(mySvc, 'save').and.callThrough();

Categories

Resources