AngularJS Time to load factory - angularjs

Hi I've create an application angular, I would login user with a call http get to WS Java. I use a view in angular, to pass parameters between views i use a factory.
My code:
I create angular module
angular.module('contactMgr',['ngRoute'])
.controller('AppCtrl',['$scope',function ($scope){}])
.config(['$routeProvider','$locationProvider',
function($routeProvider,$locationProvider){
$routeProvider.when('/',{
controller: 'homePageCtrl',
templateUrl: 'assets/partials/homePage.html'
})
.when('/login',{
controller: 'loginCtrl',
templateUrl: 'assets/partials/login.html'
})
.when('/loginError',{
controller: 'loginErrorCtrl',
templateUrl: 'assets/partials/loginError.html'
});
}])
Then add controller for login that call WS to execute login. If the WS response ID i call method load in a factory to load the user, and finally i redirect to home page
.controller('loginCtrl',['$scope','$http','$location','UserLogged',
function($scope,$http,$location,UserLogged){
$scope.loginFunction = function(){
$http({method: 'GET',
url: 'http://localhost:8080/TaskManagerWS/login/'+$scope.lg_email+':'+$scope.lg_password
}).then(function success(data,status,xhr){
$scope.idUser = data.data;
if($scope.idUser!=0){
UserLogged.load($scope.idUser);
$location.path("/");
}
else{ $location.path("/loginError"); }
},
function error(data,status,xhr){ alert("Error on call function!"); }
);
};
}])
my factory to load user
.factory('UserLogged',['$http',function($http){
var userLogged;
return{
load: function(id){
$http({
method: 'GET',
url: 'http://localhost:8080/TaskManagerWS/user/id='+id
}).then(function success(data,status,xhr){
userLogged = data.data;
},
function error(data,status,xhr){
window.alert("Error on call function!");
}
);
},
get: function(){
return userLogged;
}
}
}])
And finally my controller for home page
.controller('homePageCtrl',['$scope','UserLogged',function($scope,UserLogged){
$scope.user = UserLogged.get();
}])
All call working fine but, when i redirect to home page I don't see the result.
My home page are only tag "h1" with {{user.name}}.
But if i navigation navbar and change view and then i return to home page the title see.
Why this behavior? I would load immediately factory.
I think that angular before load page and then load factory. There is any instruction to load before factory and then page?
I try to put in the var userLogged on factory a static string and then work fine, the title load immediately. Maybe the time problem are in the $http call.
There is any method to reload view after the response of $http service?
Thanks
SOLVED:
Thanks #Matthew Cawley
I change my loginCTRL and add
UserLogged.loadCall($scope.idUser).then(function success(data,status,xhr){
UserLogged.loadFactory(data.data);
$location.path("/");
},
function error(data,status,xhr){
window.alert("Error on call function!");
}
);
}
and then i change factory to return $http in the method load and finally i add method to loadFactory to load userLogged.
There is a solution that i don't really like, but seems is the only.

It looks like you're redirecting to the home page to soon, i.e. before the UserLogged service has finished loading and set it's ownuserLogged variable to the data returned by the $http call.
This means that when you call $scope.user = UserLogged.get(); in your homePageCtrl it goes straight to the service's get method and returns nothing (because at this point userLogged hasn't been set).
Then, moments later (without really noticing it)... the $http call completes and the userLogged variable becomes set with the results but it's too late.
Solution 1: Return a promise to use in the controller
Return the promise created by the $http service by adding the return keyword:
load: function(id){
return $http({
method: 'GET',
url: 'http://localhost:8080/TaskManagerWS/user/id='+id
})
and then in your loginCtrl, change:
UserLogged.load($scope.idUser);
$location.path("/");
to:
UserLogged.load($scope.idUser)
.then(function(){
$location.path("/");
});
This way you'll only get redirected once the UserLogged.load() method has carried out it's work.
Solution 2: Pass a callback function into the service (or factory).
Create a function in loginCtrl that does a redirect:
var redirectToHome = function(){
$location.path("/");
}
Then add an extra callback parameter to the service's load() function, and execute that callback function when the promise is resolved in the service (after userLogged has been set):
load: function(id, callback) { // <---- Add extra "callback" parameter
$http({
method: 'GET',
url: 'http://localhost:8080/TaskManagerWS/user/id='+id
}).then(function success(data,status,xhr){
userLogged = data.data;
callback(); // <---- Execute the callback function (whatever it contains)
},function error(data,status,xhr){
window.alert("Error on call function!");
});
}
Then in the loginCtrl when you call services login function, do so by passing in a reference to the redirectToHome function as the callback as follows:
UserLogged.load($scope.idUser, redirectToHome); // <--- redirectToHome becomes the callback.

Related

Ensuring all Api's has been loaded in a page in AngularJS

I have 4 controllers in a page in AngularJS. Each controller calls Api's via http request(scope $http). I want to ensure that all the Api's has been called and loaded till then I can show the loading gif image. How to check all the Api's has been loaded in the page in AngulaJS.
I am not sharing the exact code some variable and name I have modified.
myApp.controller('testController',function ($scope, $http, $q, $filter) {
var _promises = {};
_promises['abc'] =
$http({
url: API_URL+'abc-type/',
method: 'GET',
params: {'test1': 'test2'}
});
_promises['abc1'] =
$http({
url: API_URL+'abc-type2/',
method: 'GET'
});
}
$q.all(_promises).then(function (res) {
alert("All promises executed.");
});
});
$http uses promises ($q) for it's API. You can use the $q.all method to run a callback when an array of $http requests are resolved (you will need to make sure all service requests return promises to avoid undefined behavior).
Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
It would look something like this
$scope.showLoadingGif = true;
$q.all([MyService.makeGet(), MyService.makeAnotherGet(), ...]).then(function(responses) {
// all the calls have returned a response by this point
$scope.showLoadingGif = false;
})

how to have angularJS post data to MVC controller which redirects to a view

I am posting some data to an MVC action method using AngularJS. This action method will either show its backing view or redirect to another page. Currently all that is happening is the data is getting posted but the redirect is not happening via MVC. I am getting this done using angular's window.location method. I want to know if there is a better way or if I need to post differently using Angular.
On page A I have angular scripts posting data to page B like below:
serviceDataFactory.POST('http://localhost:1234/home/B', someData, pageConfig).then(function () {
//on success
window.location = 'http://localhost:1234/home/Index';
},
function() {
//on error
window.location = 'http://localhost:1234/home/B';
});
This is my service factory
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
var d = $q.defer();
$http({
method: 'POST',
url: url,
data: postData,
config: conf
}).success(function(data) {
d.resolve(data);
}).error(function(error) {
d.reject(error);
});
return d.promise;
}
return service;
}
);
On Page B I want to redirect to another page. This is my page B in MVC
[HttpPost]
public ActionResult B(string someData)
{
//recieve string someData and perform some logic based on it
.
.
.
if(boolCondition)
return RedirectToAction("Index", "Home");
else
return View();
}
Here once Angular posts to the action method B, it executes all the code all the way till the if(boolCondition) statement. Since I am unable to have that redirect affected via MVC, I do that in Angular itself using the success or error block that the promise returns to.
I want to know if there is a better way to do this or if I am doing something wrong here or if this is the only acceptable way. How do I get angular to hand-off to the MVC action method and let further redirects continue from there only?
You should not use the .success() / .error() pattern with $http, because this has been deprecated. Instead, use then() with two arguments, the first argument being the success function and the second being the error function.
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
You do not need to promisify the result of $http, because $http returns a promise. Just return $http from your service.
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
return $http({
method: 'POST',
url: url,
data: postData,
config: conf
});
}
return service;
});
Your Page A controller will work the same as before with this new simplified code. At the server, be sure to emit a 500 http status code in cases where you want to trigger the
function() {
//on error
window.location = 'http://localhost:1234/home/B';
}
to run. The 500 in the headers of the response will cause the AngularJS promise to run the second function in your controller.

How to use ngResource when server is on a different localhost?

I am building an app with Ionic and MEAN stack. My express server is running on localhost:3000 while my Ionic public code is running on localhost:8100. From my research, it seems like Ionic can run on a different IP address from the server and should just use ngResource to send $http requests.
So I have a RESTful endpoint like this in server.js
router.get('/', function(req, res){
res.json({"name":"Abdul"});
});
And on the Ionic client code I am sending in a request like this:
app.controller('mainCtrl', function($scope, $resource){
$scope.test = $resource('localhost:3000/');
$scope.test_button = function(){
console.log($scope.test);
}
});
But when I click the test_button, instead of [{"name":"Abdul"}] being logged in the console, I get the following null message:
function Resource(value) {
shallowClearAndCopy(value || {}, this);
}
Can anyone help me out on connecting the client and server?
$resource object will only create an object with having get, save, update, etc. So for calling get method of server, you need to call get method of $resource object. That method will return $promise object will provide a promise. On which you can place .then promise, in which you will get data in success function.
One more thing is, when you are returning data from the server, you are returning object in array format. So in that case you need to specify get method will return array by having isArray: true option there.
$scope.test = $resource('http://localhost:3000/', {}, {get: { isArray: true}});
$scope.test.get().$promise.then(function(data){ //success function
$scope.test = data;
},function(error){ //error function
console.log(error);
})
to make your application more better, you could move up your $resource object to service/factory to make that call reusable.
app.service('dataService', function($resource){
var resourceUrl = $resource('http://localhost:3000/', {}, {get: { isArray: true} });
this.getData = function(){
return resourceUrl.get().$promise;
};
})
Controller
app.controller('mainCtrl', function($scope, dataService){
$scope.test_button = function(){
dataService.getData().then(function(data){ //success function
$scope.test = data;
},function(error){ //error function
console.log(error);
})
}
});

how to make synchronous http request in angular js

How to make blocking http request in AngularJS so that i can use the $http response on very next line?
In the following example, $http object doesn't return the result to the next line so that I can pass this result to fullcalender(), a JavaScript library, because $scope.data returns blank value.
This is the sample code:
$http.get('URL').success(function(data){
$scope.data = data;
});
$.fullCalender({
data: $scope.data
});
You can use promises for that.
here is an example:
$scope.myXhr = function(){
var deferred = $q.defer();
$http({
url: 'ajax.php',
method: 'POST',
data:postData,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
//if request is successful
.success(function(data,status,headers,config){
//resolve the promise
deferred.resolve('request successful');
})
//if request is not successful
.error(function(data,status,headers,config){
//reject the promise
deferred.reject('ERROR');
});
//return the promise
return deferred.promise;
}
$scope.callXhrAsynchronous = function(){
var myPromise = $scope.myXhr();
// wait until the promise return resolve or eject
//"then" has 2 functions (resolveFunction, rejectFunction)
myPromise.then(function(resolve){
alert(resolve);
}, function(reject){
alert(reject)
});
}
You can't, you'll need deal with it through promises, but you could try do it like this:
$http.get('URL').success(function(data){
angular.copy(data, $scope.data);
});
$.fullCalender({
data: $scope.data
});
but most people would just do
$http.get('URL').success(function(data){
$.fullCalender({
data: data
});
});
If whatever your fullCalender object is doesn't work with async data, you might need to wrap it in something like ng-if or force it to redraw when the data has been supplied. You can also force the controller to not load until the data is loaded by using the route resolve.
Here is a practical answer, courtesy of user Kirill Slatin who posted the answer as a comment. Practical use example at the bottom of the answer.
If, like me, you need to use that response object as a scope variable, this should work:
$http.get('URL').success(function(data){
$scope.data = data;
$.fullCalender = $scope.data;
$scope.$apply()
});
$scope.$apply() is what will persist the response object so you can use that data.
-
Why would you need to do this?
I'd been trying to create an "edit" page for my recipes app.
I needed to populate my form with the selected recipe's data.
After making my GET request, and passing the response data to the $scope.form, I got nothing... $scope.$apply() and Kirill Slatin helped big time. Cheers mate!
Here's the example from my editRecipeController:
$http.get('api/recipe/' + currentRecipeId).then(
function (data) {
$scope.recipe = data.data;
$scope.form = $scope.recipe;
$scope.$apply()
}
);
Hope that helps!

AngularJS $rootScope loses value unless I use promise (trigger.io AJAX request)

So this is quite weird. $rootScope is getting set correctly within a function, but then loses its value. I can only keep the value if I use a promise. (!?)
I am using a trigger.io (Forge) AJAX request, and upon success I update $rootScope.queries. Within the success block, $rootScope.queries is set correctly, as shown by the alert.
.run(function($rootScope, $state, $q) {
var retrieveHistory = function() {
forge.logging.log("Retrieving history");
// Retrieve the history
forge.request.ajax({
type: 'GET',
url: 'http://localhost:9000/json',
dataType: 'json',
success: function (data) {
$rootScope.queries = data["queries"];
alert("queries " + JSON.stringify($rootScope.queries));
},
error: function (error) {
}
});
}
retrieveHistory();
At this point though, after retrieveHistory() has been called, $rootScope.queries is now empty. The view doesn't update and inspecting using the Chrome console shows that it is empty.
Let's say I add a promise to the function, but don't really use the promise for anything.
.run(function($rootScope, $state, $q) {
var retrieveHistory = function() {
var deferred = $q.defer();
forge.logging.log("Retrieving history");
// Retrieve the history
forge.request.ajax({
type: 'GET',
url: 'http://localhost:9000/json',
dataType: 'json',
success: function (data) {
$rootScope.queries = data["queries"];
alert("queries " + JSON.stringify($rootScope.queries));
},
error: function (error) {
deferred.reject("error " + JSON.stringify(error));
}
});
return deferred.promise;
}
var promise = retrieveHistory();
promise.then();
With this promise, $rootScope.queries keeps its value. The view updates and Chrome inspector shows the value is set correctly.
Why is this? I simply don't understand this behavior. Why can't I preserve the value of $rootScope.queries in the original code? Why does the promise keep the value?
ok, 2 questions.
why are you using trigger.ajax over $http pr resource which are angular native services hence are fully aware of angulars diges cycle not the case of external libraries.
why are you using rootscope you really shouldn't do that unles you are broadcasrting an event inside a service i know no good reason to polute your rootscope.
How ever your problem is likely to be doe to forge.ajax being outside angular digest so you need to execute.
$rootScope.$apply()
to let rootscope know there are somechangins he needs to be aware of

Resources