Angularjs rootscope value is undefined within the same controller in same function - angularjs

I have set the username value in rootscope and when I try to use it within the same function it becomes undefined. I am not sure why this is happening.
controller
xxxApp.controller('listController', function($scope, $http, $location, $routeParams, $log, uiGridConstants, $rootScope) {
$scope.isSelected = false;
$scope.showSpinner = true;
$rootScope.loggedInUser = {};
$scope.user = {};
$http.get("/mdm/getLoggedInUsername")
.success(function(data, status, headers, config) {
$scope.user = data.user;
$rootScope.loggedInUser = $scope.user;
console.log("the logged in user is 1" +$scope.user);
console.log("the rootscope logged in user is 1" +$rootScope.loggedInUser);
})
.error(function(data, status, headers, config, statusText) {
console.log("Error ....the logged in user is 1" +$scope.user);
});
console.log("the rootscope logged in user is 2" +$scope.user);
$http.get("/mdmservice/services/entities/" +$rootScope.loggedInUser) // here rootscope is undefined and throws me 404 error not found
.success(
function(data, status, headers, config) {
$scope.entities = data;
})
.error(function(data, status, headers, config, statusText) {
$scope.error = true;
$scope.errorMessage = "A system error occured."
})
.finally(function () {
$scope.showSpinner = false;
});

That happens because $http calls are asynchronous - that means your program executes in the following order:
start first http call
print console log statement
start second http call
execute the success or error callbacks once the respective http call is finished
So to make your script work you can put the console.log statement and your second http call within the success callback of the first http call.
If you have trouble understanding this, I would recommend reading up on asynchronous programming in javascript with Callbacks and Promises.

That's because the first get function hasn't finished yet. You should call the second in callback of the first (in success area).

Related

Add Delay in angularjs

I want to add some delay in angularjs. So that it can fetch data from api. Because my api is heavy. I am calling this function. Basically i want some delay to load page so that my api work properly. I tried some time my data pull immediate some time i am getting error. When i refresh my page it work fine.
Help to put $timeout function in this angularjs
// Geting test stuff
$scope.teststuff = function () {
$scope.loading = true;
$http.get(settings.WebApiBaseUrl + 'Api/testing')
.success(function (data) {
$scope.mydata = data;
$scope.loading = false;
}).error(function (data, status, headers, config) {
alert("Error " + status )
$scope.loading = false;
})
}
Updated:
This problem can easily be solved by using resolve property of $routerProvider. Please use this config. So here the route /ed will not load until the resolve is completed, meaning the http request must return a value, only after that the page will load.
app.config(['$routeProvider', '$httpProvider', function ($routeProvider, $httpProvider) {
var settings.WebApiBaseUrl = "some url you want to use";
$routeProvider.when("/al", { templateUrl: "Views/test.html", controller: "testCtrl" })
.when("/ed", {
templateUrl: "Views/test2.html",
controller: "test2Ctrl",
resolve: {
initialize: function($http, $sessionStorage){
$http.get('api/ApiKey/' + $sessionStorage.user)
.success(function (myKey) {
return $http.get(settings.WebApiBaseUrl + 'Api/test1', { headers: { 'X-ApiKey': myKey } })
.success(function (data) {
return data;
}).error(function (data, status, headers, config) {
alert("error" + status);
});
}).error(function (data, status, headers, config) {
alert("error" + status);
});
}
}
})
.otherwise({
redirectTo: '/al'
});
}]);
Now in the controller you need to do.
app.controller( 'test2Ctrl', function ( $scope, initialize ) {
$scope.loading=false;
$scope.test1=initialize;
$scope.loading=true;
});
Old Answer:
so you have a http request which is a promise and will wait until the data is received and from your example I can see you are implementing a loading screen kind of thing until the http request is completed.
To ensure the bulky http request doesn't time out you can use.
angular.module('MyApp', [])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.timeout = 5000;
}]);
While the page waits for the http request to complete you can use the scope variable($scope.loading = true;) to activate a loading spinner library to mask your page. Checkout angular loading overlay or some other code to do this.
Reference:
http timeout

AngularJS Event - dom is delayed updating

In my app, I have an event that listens for new messages sent to a user. Upon receiving the event, it runs a factory function to retrieve messages. However, it seems as though it is always 1 event behind (ie, event 1 data doesn't display until event 2 occurs).
I have a feeling this has to do with the digest cycle. I have tried $scope.$apply, $timeout to no avail. Hopefully I have been clear enough.
$scope.retrieveMessages = function(){
Conversations.retrieveConversations($scope.authentication.uid)
.then(function(success){
$scope.messageList = success;
}, function(error){
console.log(error);
});
};
$scope.$on('$RECEIVED_MESSAGE', function (event, data) {
$scope.retrieveMessages();
$scope.$apply();
});
Service
angular
.module('conversations')
.factory('EventEmitter', ['$rootScope',
function($rootScope) {
var factory = {
newMessage: function() {
$rootScope.$broadcast('$RECEIVED_MESSAGE');
}
};
return factory;
}]);
Function in controller that watches firebase for changes
var notificationsRef = new Firebase(config.firebaseRef + 'notifications/' + $scope.authentication.uid);
notificationsRef.limitToLast(1).on('child_added', function(childSnapshot, prevChildKey) {
var snapshot = childSnapshot.val();
if(snapshot.type === 'Conversation'){
EventEmitter.newMessage();
};
})
.catch(function(error) {
console.error("Error:", error);
});
Conversations Factory (omitted definition and other methods for brevity)
retrieveConversations: function(uid){
var deferred = $q.defer();
var request = {
uid: uid
};
$http.post(config.serverRef + '/conversations', request)
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
deferred.reject(status);
});
return deferred.promise;
},
Issue was not with the code but timing and execution. Calls were happening faster than the re-indexing of firebase data to elasticsearch. Solved with $timeout(function(){$scope.retrieveMessages()}, 1000).

Asynchronous call: call a function upon receiving first "pending" response by server

I have an asynchronous web service which will return status "pending" immediately until it returns either 200 or an error.
This is my code so far:
$http.get('/myweb/services/callService').success(function(response, status, headers, config){
...handling success
}).error(function(err, status, headers, config){
//handling failure
});
//called just after $http.get
$scope.askProgress();
Where askProgress is:
$http.get('/myweb/services/progress').success(function(response, status, headers, config){
console.log(response);
$scope.reportProgress = response.description;
if(response.description < 100){//description is a 0-100 value indicating progress
...updating status...
$timeout(function() {$scope.askProgress();}, 1000); //calling again
}else{
$scope.reportProgressL = "Done!";
}
}).error(function(err, status, headers, config){
alert('Error: '+err+" "+status);
});
My problem is that the first call to askProgress is made before the service returns status "pending" leading to a non consistent progress value.
I'd like for the askProgress function to be called just after the service gives me the first "pending"...is it possible?
Not sure I understand you problem fully but it sounds like you need to be calling your askProgress() function after the first http request returns. If so, have you tried putting the call inside your then() call?
$http
.get('/myweb/services/callService')
.then(function(response, status, headers, config){
return $scope.askProgress();
})
.then(function(progressResponse){
})
.catch(function(error){});
Update
I think you will need to register an $http interceptor to track the state of your request.
Try this:
DEMO
app.js
var app = angular.module('plunker', []);
app.factory('myHttpInterceptor', [ function() {
var pendingRequests = {};
return {
getPendingRequests: function(){
return pendingRequests;
},
request: function(request) {
console.log('*** request made # %s ***', new Date());
pendingRequests[request.url] = true;
console.log('pendingRequests', pendingRequests);
console.log('**************************');
return request;
},
response: function(response) {
console.log('*** response received # %s ***', new Date());
var url = response.config.url;
if(pendingRequests.hasOwnProperty(url)){
delete pendingRequests[url];
}
console.log('pendingRequests', pendingRequests);
console.log('**************************');
return response;
}
};
}]);
app.config(['$httpProvider', function($httpProvider) {
// register our factory as an http interceptor
// in the config phase
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
app.controller('MainCtrl', function($scope, $http, $timeout, myHttpInterceptor) {
var targetUrl = 'big-data.json';
$scope.callService = function(){
console.log('*** call service ***');
return $http.get(targetUrl)
.then(function(){
console.log('********** done, success **********');
})
.catch(function(){
console.log('********** done, error **********');
});
}
$scope.askProgress = function(){
var pendingReqs = myHttpInterceptor.getPendingRequests();
// the request in this demo is very quick
// so I have had to change the time between checks
// you will probably want to change this for your
// own app
return $timeout(1)
.then(function(){
if(pendingReqs.hasOwnProperty(targetUrl)){
console.log('*** stil pending ***');
return $scope.askProgress();
}
console.log('*** no pending requests ***');
$timeout.cancel();
})
}
$scope.callService();
$scope.askProgress();
});

Data from the factory when referenced to a scope does not show the value. AngularJS

I'm quite new on AngularJS and got stumped on a problem. I'm trying to get a value from a factory and was able to get the data, I attached a console.log() to the function to check, but when I tried to attached these data on a scope and do a check using console.log again, I’m getting a undefined message on the log.
I tried creating an object scope $scope.formWO= {}; and references it there but still I’m getting the same message. I don’t know if there are conflicts between scopes or an issue of displaying the page early before the system read or perform the function. I already read a lot on scopes but for somehow this problem seem to put my development into a complete stop. I don’t know which is which and would like definitely to get enlightened on this.
Here is the trimmed down controller just to give you an idea.
myApp.controller('ordersCtrl',
function ordersCtrl($scope, ngTableParams, dealerData, costElementData, totNoData, $http, $ekathuwa, $rootScope, $location, userService, $filter){
$scope.formWO = {};
$scope.addWorkOrder = function(){
$scope.modalHeader = "ADD NEW WORK ORDER";
$scope.modalType = "Add";
$ekathuwa.modal({
id: "modalWO",
scope: $scope,
templateURL: "./tpl/modal-wo.html"
});
$scope.$watch('formWO.dealer', function(newDealer, oldDealer){
if ( newDealer === oldDealer) {
return;
}
$http.get('api/profile/'+$scope.formWO.dealer).
success(function(data, status, headers, config){
$scope.formWO.outletno = data.outletno;
});
if ($scope.dealer === newDealer) {
return;
}
});
}
$scope.submitAddWorkOrder = function(cost_element, desc, ets, etc, cost_estimate, dealer){
totNoData.getTotNo(function(noData){
$scope.formWO.totno = noData;
});
console.log($scope.formWO.totno);
$scope.tableParams.reload();
}
});
Here is the factory:
myApp.factory('totNoData', function($http, $log){
return {
getTotNo: function(successcb){
$http({method: 'GET', url: 'api/totno'}).
success(function(data, status, headers, config){
successcb(data);
}).
error(function(data, status, headers, config){
$log.warn(data, status, headers, config);
});
}
}
});
What you probably want to do is move the log and, I guess, the reload, inside of the anonymous callback function that you're passing to 'getToNo'. Like:
$scope.submitAddWorkOrder = function(cost_element, desc, ets, etc, cost_estimate, dealer){
totNoData.getTotNo(function(noData){
$scope.formWO.totno = noData;
console.log($scope.formWO.totno);
$scope.tableParams.reload();
});
}
As it is, the log and the reload are happening before the callback is invoked. The order would go something like this:
call the getTotNo method
send the http request
step back out to submitAddWorkOrder
log $scope.formWO.totno (undefined)
call $scope.tableParams.reload();
... event loop / digest
http response received, success method called
callback invoked
$scope.formWO.totno is set
Async for the win!
EDIT:
A better to pattern is to return the promise that is returned from the $http call.
So change the service to:
getTotNo: function(){
return $http({method: 'GET', url: 'api/totno'});
}
And refactor your controller function to:
$scope.submitAddWorkOrder = function(cost_element, desc, ets, etc, cost_estimate, dealer){
totNoData.getTotNo().success(function (data) {
$scope.formWO.totno = noData;
console.log($scope.formWO.totno);
$scope.tableParams.reload();
}).error(function (data, status, headers, config) {
$log.warn(data, status, headers, config);
});
}

Assign variable from $http .success function to $scope.variable

$scope.restaurants variable is emty. how to pass data to $scope.restaurants?
FoodSearchControllers.controller('homeCtrl', ['$scope', '$http', function($scope, $http) {
//restoranai
$http.post('http://appdev.milasevicius.com/server/index.php', {
"query": "SELECT * FROM n01_restaurant"
}).success(function(data, status) {
$scope.restaurants = data;
}).error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
console.log($scope.restaurants);
}]);
Also, controller is called twice. Why is that?
Your console.log is called at a point where the $http call might not have returned yet. The post is an async call so if you move your console.log in your success function, you should see it. In short, $scope.restaurants is mostly likely being populated but you're trying to check it too early.

Resources