Angular JS Root Scope - javascript

I am working with angular js at view layer. I need to use some global variable that will be used and modified by all the controllers method in my application:
var app = angular.module('myWebservice', ['ngCookies']).run(
function($rootScope) {
$rootScope.authToken = null; });
app.controller('UserController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.login= function() {
$http.defaults.headers.post = {'Accept' : 'application/json',
'Content-Type' : 'application/json'};
$http.post('/myServise/api/user/login-user', {
emailId : $scope.username,
password : $scope.password
}).success(function(data, status) {
if (status == 200) {
$rootScope.authToken = data.object.authToken;
}).error(function(data, status) {
console.debug(data);});
}// Else end
};// End Login
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.getRootScopeValues = function()
//$scope.getRootScopeValues = function($rootScope)
{
$scope.token = $rootScope.authToken;
console.log($scope.token);// Undefined
console.log($rootScope.authToken);// Undefined
}
});
I am new to Angular JS, I have also tried to use service but I don't know why I am not able to access global variable (authToken). Please help me I am stuck at this point ....Thanks in advance...

I am not sure how your application works but looks like you have a problem of asynchronous calls (while $http is working you are trying to access the variable which is not set yet). Please look at this answer about Asynchronous calls. Maybe this is your case? Also I should note that using $rootScope is always a bad idea. Try to avoid it. You should use service instead which is also a singleton object and always a much better and maintainable approach.

I need to use some global variable that will be used and modified by all the controllers method in my application
The best way to achieve this is using a Service, but you don't have to if you would like to leave it at the $rootScope
I have tried to use service as well but same results "Undefined"
Because the call for the authToken is asynchronous, the controller could run before the token returns from remote server.
You can add the token retrieval logic to the route definition as a 'resolve' field like this:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/your/route', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
token: function() {
//return a promise with the token here
}
}
})
However, this is NOT good in your case as you will have to setup the 'resolve' for every route. If you are using AngularUI Route that supports nested routes, you can simply add the 'resolve' to the root state/route. This is what I've been using in my project.
If you are not using AngularUI Route, there's another way of doing it. You can assign the returned value of the $http.post to a variable in the $rootScope e.g. $rootScope.tokenPromise.
The returned of $http.post is a promise, you can use the 'then; method to register callbacks, and these callbacks will receive a single argument – an object representing the response.
In your controller, you will have put some extra lines, you will get the token asynchronously like this
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$rootScope.tokenPromise.then( function(token){
console.log(token); //depends on the returned data structure
} )
});
In your application 'run' block, you will have to create a promise at $rootScope.tokenPromise. you can either use $http to retrieve the token and get the promise there in the run block, or create a pending promise and retrieve the token elsewhere in other places, after which you can resolve the promise.

Related

AngularJS Async isolated directive is not working

I want to send an object returning from the DB to a child directive. When I am sending any kind of data in sync mode it works. However when I am doing the same thing but fetching the data from remote server - async method, the directive is getting fired before the results are coming.
This is the controller which fetched the data from the server:
app.config(function($routeProvider, $locationProvider) {
$routeProvider.when("/root/cardboards/employees/:_employee", {
templateUrl: "screens/root/cardboards/employees-detail/employees-detail.html"
});
// $locationProvider.html5Mode(true);
});
app.controller("employees-detail", ($rootScope, $scope, $location, $routeParams, Http, Cast) => {
Http.GET({
resource: `employees/${$scope._employee}`
}, (err, response) => {
if (err) return Cast.error(err);
$scope.employee = response.data; // employee's object
$scope.$apply();
});
});
This is the directive element in HTML:
<edit-employee employee="employee"></edit-employee>
And this is the edit-employee directive js file:
app.directive("editEmployee", ($rootScope, Http, Cast) => {
return {
templateUrl: "/screens/root/cardboards/employees-detail/components/edit-employee/edit-employee.html",
scope: {
employee: "="
},
link: function($scope, element, attrs) {
console.log($scope.employee); // undefined
}
}
});
I thought that when I am using the = operator it means that it's now two way binding and the directive will watch for changes and then having the functionality based on the data that will come after the request to the server.
However it doesn't work like that.
How should it work and what should I do, the standard way, to make thing working?
When <edit-employee being rendered it will try to get the employeeto do a console.log on this line
link: function($scope, element, attrs) {
console.log($scope.employee); // undefined
}
But unfortunately, at that time, the employee is still undefined since it waiting for the response from the server.
To understand more clearly about this you can initiate a $watch to watch the employee inside edit-employee directive, and whenever the HTTP is finished it will update the employee to newest value.
How should it work and what should I do, the standard way, to make thing working?
It really depends, I meet that problem once and I used an ng-if on <edit-employee ng-if='employee' which mean the edit-employee directive will be rendered after the employee is initial (!= undefine).
Another way is you watch the employee inside edit-employee directive and check if employee has value then continue the business logic

[JavaScript][Angular]: TypeError: Cannot read property 'getCityData' of undefined

This question has been asked many times before and I've tried the answers but they do not seem to solve the problem I'm facing. I'm new to Angular and am trying to pass a value from the controller to a factory so that I can retrieve some JSON information through an API. While I'm able to get the value from my HTML to the controller, the next step is giving me a TypeError: Cannot read property 'getCityData' of undefined. My controller code is as follows:
app.controller('MainController', ['$scope', function($scope, HttpGetter) {
var successFunction = function(data) {
$scope.data = data;
}
var errorFunction = function(data) {
console.log("Something went wrong: " + data);
}
$scope.cityName = '';
$scope.getCityName = function(city) {
$scope.cityName = city;
HttpGetter.getCityData($scope.cityName, successFunction, errorFunction);
};
}]);
The factory code is as follows:
app.factory('HttpGetter', ['$http', function($http){
return {
getCityData: function(query, successFunction, errorFunction){
return $http.get('http://api.apixu.com/v1/current.json?key=MyAppKey&q=' + query).
success(successFunction).
error(errorFunction);
}
};
}]);
I've replaced my App key with the string "MyAppKey" just to be safe but my code contains the appropriate key. Also, it would be very helpful if I could get a bit of an insight on how the function invocations happen because there seem to be a lot of function callbacks happening.
Getting undefined could be because of the service not getting properly injected.
Try:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
Also as you said, to be on safer side you aren't using the right key, but anyone using your application can get the key by checking the network calls. So, ideally, one should make a call to the backend, and backend will send a call along with the secured key to the desired API endpoint and return the response data to front-end.
Can be due to ['$scope', function($scope, HttpGetter) ?
Should be ['$scope', 'HttpGetter', function($scope, HttpGetter) instead.
You used minified version and inject only $scope not HttpGetter but used as argument in controller function that's why got HttpGetter is undefiend and error shown Cannot read property 'getCityData' of undefined
So you should inject HttpGetter in your minified version ['$scope', 'HttpGetter'
use like:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
instead of
app.controller('MainController', ['$scope', function($scope, HttpGetter)
And if your MyAppKey is secured and want to hide from user then you should use it in server side

Trying to persist data across controllers using Angular rootScope, but always getting undefined

I have an administrator login page. When a user successfully logs in as an admin, I want to display at the top of all pages the user visits:
<!-- nav bar -->
<div>
<span ng-show="$root.isAdmin">(ADMIN)</span>
</div>
I tried using $rootScope to accomplish this, but I keep getting undefined:
// controller for logging in
app.controller('AdminLoginCtrl', [ '$rootScope', '$scope', 'stateParams', 'loginService', function($rootScope, $scope, $stateParams, loginService) {
loginService.success(function() {
$rootScope.isAdmin = true;
console.log($rootScope.isAdmin); // returns true
$location.path("/login_success");
});
}]);
// some other controller AFTER user is logged in as admin
app.controller('BlahCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
console.log($rootScope.isAdmin); // returns 'undefined'
});
There have been some other similar topics, but don't apply to me:
(I don't have an injection problem):
$rootscope value undefined in Controller
(My other controller is definitely being called AFTER login, so $rootScope.isAdmin should be set):
AngularJS - Cannot access RootScope
(I don't have an ordering problem):
Angular $rootScope.$on Undefined
The other solution could be to not use $rootScope at all, and just use a service to hold shared data. But if I have 10+ controllers, is it acceptable to do this in each:
app.controller('...', ['$scope', 'checkAdminService', function($scope, checkAdminService) {
$scope.isAdmin = checkAdminService.getIsAdmin()
}]);
Then:
<span ng-show="isAdmin">(ADMIN)</span>
Is this acceptable or more cumbersome? And for completeness sake, why doesn't $rootScope solution work at all?
It's indeed a bad practice using the $rootScope. The best solution is what you propose yourself to create a service storing the information you want to share between different controllers. It is no problem to call this method on several locations...
Why don't you define a separate controller for the top-part of your page which will be the only one verifying whether the user is an admin? The other part of your page can be controller by different controllers.
This example will explain how to use several controllers, but of course this can also be achieved via Routers.
What if you replace the $rootScope that you're passing around with a special-purpose angular value that you can register at startup and pass around as needed?
http://plnkr.co/edit/r6kdouh0BbnYA4DmEcEM?p=preview
angular
.module('app')
.value('userProfile', userProfile);
function userProfile() {
var userProfile = {
isAdmin: false
};
return userProfile;
}
/////////////////
angular
.module('app')
.run(run);
run.$inject = ['userProfile', 'userAuthService'];
function run(userProfile, userAuthService) {
userAuthService.isUserAdmin().then(function(result) { userProfile.isAdmin = result; });
}
angular.module('yourmodule', [])
.run(['$rootScope', function($rootScope) {
$rootScope.isAdmin = true;
])

AngularJS $http return value

I am new to AngularJS and only aware of the basics of AngularJS. I want to return a value from $http. That is $http should return a value to the global variable of My Application.
I have tried this:
var sessionValues = null;
var AdminController = angular.module('AdminController', []);
AdminController.controller('LoginController', ['$scope', '$http','$location',
function ($scope, $http, $location){
$http({
method: "post",
url: "API/MyPage.php",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data){
sessionValues = eval(data);
console.log(sessionValues); /*Returns desired string*/
}).error(function(){
$scope.message="Some error has occured";
});
console.log(sessionValues); /*Returns null */
}
]);
I tried using $rootScope, but was not successful.
I understand that this is because it is an asynchronous call, but how can I fetch the value in JS's global variable.?
Can anyone help me about this.?
The problem is indeed with the async nature of call and when you are trying to access the variable. console.log returns null because it gets called before the $http call is complete.
Firstly we do not pollute the JavaScript global scope, but use services\factory, $rootScope to access data.
In you case if you want to expose a variable to across angular, the easiest way is to use $rootScope. Something like this
AdminController.controller('LoginController', ['$scope','$http','$location','$rootScope'
function ($scope, $http, $location,$rootScope){
$http({
method: "post",
url: "API/MyPage.php",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data){
$rootScope.sessionValues = eval(data);
console.log($rootScope.sessionValues); /*Returns desired string*/
}).error(function(){
$scope.message="Some error has occured";
});
console.log($rootScope.sessionValues); /*Returns will always null due to async nature call*/
}
]);
You then have to access that variable only after it has been filled in the success call back, before that it would be always null. The console.log would always fail.
To know when the variable value has changed you can use AngularJS watch http://www.benlesh.com/2013/08/angularjs-watch-digest-and-apply-oh-my.html
I think what you want is to retrieve a constant from backend service before application loaded.
You can refer to How to retrieve constants for AngularJS from backend
In your controller, you can get the APP_CONFIG directly.
AdminController.controller('LoginController', ['$scope', '$http','$location','APP_CONFIG'
function ($scope, $http, $location, APP_CONFIG){
});
You can reuse APP_CONFIG at any angular controller, service or factory.

Angularjs - Passing API Data between two controllers

i want to share data that i get from the lastFM API between two controllers.
I've been trying with the factory but I don't get a grip on it...
angular.module('myApp')
.factory('getData', function($http, $scope, $routeParams) {
$http.get(lastfm + "&method=artist.getInfo&mbid=" + $routeParams.mbid).success(function(data) {
console.log(data)
});
})
.controller('artistCtrl', function ($scope, $routeParams, $http, getData) {
console.log(getData.data);
})
.controller('artistInfoCtrl', function ($scope, $routeParams, $http, getData) {
console.log(getData.data);
})
So how do i manage to pull this off?
There are a couple of things:
1) know that you're dealing with asynchronous data, so do not expect to be able to read the data in the controllers immediately.
2) have your factory return a function that the controllers can call. This function should return a promise that will eventually (if all goes well) be resolved with the data;
3) the controllers can call this function that is returned by the factory and in the .then() of the promise that is returned, you can actually work with the data.
My advice is to do a little research on the terms I described above, if they are not yet familiar to you. Understanding them will enable you to achieve a lot more with angular.
Your factory has no property data, you probably need to call your factory by saying
var something = getData();
and make the success handler of the $http call return that data
$http.get(lastfm + "&method=artist.getInfo&mbid=" + $routeParams.mbid).success(function(data) {
return data;
});

Categories

Resources