AngularJS: On GetJSON complete use the data in other controller - angularjs

I'm newbie in Angular.
// This is my main controller
app.controller('AppCtrl', ['$rootScope', '$scope', 'cfpLoadingBar', '$http',
function ($rootScope, $scope, cfpLoadingBar, $http) {
cfpLoadingBar.start();
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
//stop loading bar on stateChangeSuccess
event.targetScope.$watch("$viewContentLoaded", function () {
// HERE I want to send request to API and on complete do
// 1. Complete loadbar
// 2. Write response to global var and use it from other controller
$http.get(
'/api/',
{}
).then(function (response) {
// Completing loadbar
cfpLoadingBar.complete();
$SOME_GLOBAL_VAR.api = response;
});
});
});
}]);
// Controller 1
app.controller('Ctrl_1', ["$scope", "$http" function ($scope, $http) {
$scope.param = 'get_data_1';
When $SOME_GLOBAL_VAR.api
console.log($SOME_GLOBAL_VAR.api);
}]);
I want to use one api request for different controllers.
So I want to load API, and when it finish - each controller will render his part.
Now I can't understand how to listen to API loading is completed?

You can achieve this in following way
$http.get(
'/api/',
{}
).then(function (response) {
// Completing loadbar
cfpLoadingBar.complete();
$rootScope.$emit("receivedApiUpdate", response);
});
angular.module("my_module")('controller1', ['$rootScope', function($rootScope) {
$rootScope.$on('receivedApiUpdate',function(event, response){
// Do your work
});
}]);
angular.module("my_module")('controller2', ['$rootScope', function($rootScope) {
$rootScope.$on('receivedApiUpdate',function(event, response){
// Do your work
});
}]);
angular.module("my_module")('controller3', ['$rootScope', function($rootScope) {
$rootScope.$on('receivedApiUpdate',function(event, response){
// Do your work
});
}]);

you can try to make a service and use your service across your controllers.
https://docs.angularjs.org/guide/services

Related

services throwing error in the controller as function not defined

amcApp.service('utilService', function ($http, $q,$rootScope) {
var getSupportTypes = function () {
var deferred = $q.defer();
$http.get($rootScope.BaseUrl+'vendor/supportTypes')
.then(function daoSuccess(response) {
console.log("Getting Sub Customer Service call success ", response);
deferred.resolve(response);
}, function daoError(reason) {
console.log("Getting SubC data service call error", reason);
deferred.reject(reason);
});
return deferred.promise;
};
return{
getSupportTypes : getSupportTypes,
};
});
Above is the service I defined.
Below is the controller I defined.
amcApp.controller('contractForm', ['$scope', '$http','$rootScope','$filter', '$uibModal', '$state', 'testService','utilService','contractService',
function ($scope, $http,$rootScope, $filter,$uibModal, testService,utilService,contractService) {
//Service of getting the Support Types.
utilService.getSupportTypes().then(function(response){
$scope.supportTypes = response.data.UtilDataType;
});
}]);
This is the error I'm getting:
Can I get any suggestions?
Check the dependencies what you inject into the controller, you have an extra $state in the array which has not been passed to the function. I would suggest to remove as the following:
amcApp.controller('contractForm', ['$scope', '$http', '$rootScope', '$filter', '$uibModal', 'testService','utilService','contractService',
function ($scope, $http, $rootScope, $filter, $uibModal, testService, utilService, contractService) {
//Service of getting the Support Types.
utilService.getSupportTypes().then(function (response){
$scope.supportTypes = response.data.UtilDataType;
});
}]);
On the other hand I would simply remove all the not used services, I assume this is working also fine:
amcApp.controller('contractForm', ['$scope', 'utilService', function ($scope, utilService) {
//Service of getting the Support Types.
utilService.getSupportTypes().then(function (response) {
$scope.supportTypes = response.data.UtilDataType;
});
}]);
Just a suggestion - if you keep your code clean it is much easier to figure out the root cause of any issues.

Global $http.get() that updates every 5 seconds across all scopes/controllers in Angular 1.5

In my Angular project I am loading json list from my api that is constantly updating. I would like to have this update every 5 seconds across all my angular controllers without making a new request per controller.
Why not just have a service make the API call on an $interval, then $broadcast a message and the data each time the promise with updated data is fulfilled.
angular.module('app')
.service('PollingService', ['$http', '$rootScope', '$interval', function($http, $rootScope, $interval) {
var updatedData;
$interval(function() {
return $http.get(apiUrl).then(function successCallback(response) {
updatedData = response.data.data;
$rootScope.$broadcast('got new data!', { data: updatedData });
}, function failureCallback(reason) {
console.log(reason);
})
}, 5000);
}]);
And then listen for the broadcast in all the controllers that need the updated data:
angular.module('app')
.controller('someCtrl', ['$scope', function($scope) {
$scope.$on('got new data!', function(event, args) {
$scope.data = args.data;
});
}]);

Send event after controller has bean loaded

I have two controllers, when user press the button to load SeconvView, the FirctCtrl sends event to the SecondCtrl via $rootScope.$broadcast.
// FirstCtrl.js
app.controller('FirstCtrl', ['$scope', function($rootScope, $scope) {
// ...
$scope.emitEvent = function(){
console.log("Emitting event");
$rootScope.$broadcast("EventName", "event data");
}
}]);
// SecondCtrl.js
app.controller('SecondCtrl', ['$scope', function($rootScope, $scope) {
console.log("Hola from SecondCtrl");
$rootScope.$on("EventName", function(event, data){
console.log(data);
});
}]);
Log output:
Emitting event
Hola from SecondCtrl
So, the problem is that SecndCtrl can't catch the event. I think that this is because the events sends before SecondCtrl is loaded.
With little timeout i can solve this problem, but ... common, i must use timeout for this :/
// FirstCtrl.js
app.controller('FirstCtrl', ['$scope', function($rootScope, $scope) {
// ...
$scope.emitEvent = function(){
$timeout(function() {
console.log("Emitting event");
$rootScope.$broadcast("EventName", "event data");
},100);
}
}]);
Log output:
Hola from SecondCtrl
Emitting event
event data
Some better way to solve this ?
Passing data between controllers is one of the main uses of a service / factory instead
// FirstCtrl.js
app.controller('FirstCtrl', ['$scope', function(MyFactory, $scope) {
// ...
$scope.emitEvent = function(){
console.log("Emitting event");
MyFactory.storedvalue = "event data";
}
}]);
// SecondCtrl.js
app.controller('SecondCtrl', ['$scope', function(MyFactory, $scope) {
console.log("Hola from SecondCtrl");
console.log(MyFactory.storedvalue);
});
}]);

Angular $q and $http for data binding not working

I'm trying to make a basic data pulling using a service and print it on screen when I have data, but something is not working.
My service:
mymodule.factory('MyService', function($http, $q) {
var service = {
getData: function() {
var dfd = $q.defer();
$http.get(apiServerPath).success(function (data) {
dfd.resolve(data);
});
return dfd.promise;
}
}
return service
}
My Controller:
mymodule.controller('myCtrl', ['$scope', 'MyService', function($scope, MyService) {
$scope.myvar = MyService.getData();
}
HTML
<div> {{myvar}} </div>
What I can see from the browser console -
The myvar object turn into a promise object
The success function is being called and 'data' has valid data in it
And for my question and issue - the controller's variable does not change when the defer object is resolving - why?
Promises are no longer auto-unwrapped as of Angular 1.2. In your controller do the following:
mymodule.controller('myCtrl', ['$scope', 'MyService', function($scope, MyService) {
MyService.getData().then(function success(data) {
$scope.myvar = data;
});
}

Unit testing angular-ui router maximum callstack

I'm new to angular-ui-router and I've been trying to do some unit testing for a basic authentication, its working fine until I hit a maximum call stack error.
I've narrowed the error down to the $state.go call in the app.run section.
I remove this and the test works. However it breaks my app
What can I do to resolve this? so I can test this section and make it work as well?
Why does this work normally but causes a test error?
Error:
RangeError: Maximum call stack size exceeded
at Scope.$broadcast (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular/angular.js:12876:15)
at Object.transitionTo (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular-ui-router/release/angular-ui-router.js:2584:24)
at Object.go (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular-ui-router/release/angular-ui-router.js:2454:21)
at /Users/paulrobinson/Workspace/contactCachePOC/dev/js/core.js:9:5889
at Scope.$broadcast (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular/angular.js:12874:28)
at Object.transitionTo (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular-ui-router/release/angular-ui-router.js:2584:24)
at Object.go (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular-ui-router/release/angular-ui-router.js:2454:21)
at /Users/paulrobinson/Workspace/contactCachePOC/dev/js/core.js:9:5889
at Scope.$broadcast (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular/angular.js:12874:28)
at Object.transitionTo (/Users/paulrobinson/Workspace/contactCachePOC/dev/bower_components/angular-ui-router/release/angular-ui-router.js:2584:24)
Code:
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
var access = routingConfig.roles;
$stateProvider
.state('start', {
url : '/',
templateUrl : 'partials/decide.html',
controller : 'decideController',
data: {
access: access.anon
}
});
}]);
app.run(['$rootScope', '$state', 'AuthService', '$log', '$location',
function ($rootScope, $state, AuthService, $log, $location) {
$rootScope.$on("$stateChangeStart",
function (event, toState, toParams, fromState, fromParams) {
if (!AuthService.isAuthorized(toState.data.access)) {
event.preventDefault();
$rootScope.error = null;
//STATE.GO is causing the error
$state.go('start');
//$location.path('/#/');
return;
}
});
}]);
describe('Test as an anonymous user', function () {
var $templateCache, $state, $stateParams, $rootScope, $httpBackend,
AuthService,, $location;
var roles = {
anon: { id: 0, value: 'Public'},
user: { id: 1, value: 'User'}
};
beforeEach(module('app'));
beforeEach(inject(function(_$templateCache_, _$state_, _$stateParams_, _$rootScope_, _$httpBackend_,
_AuthService_, _sessionService_, _$location_) {
$templateCache = _$templateCache_;
$state = _$state_;
$stateParams = _$stateParams_;
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
AuthService = _AuthService_;
$location = _$location_;
//Fake it and say we're not authorized.
spyOn(AuthService, "isAuthorized").andCallFake(function (state){
return false;
});
}));
describe('View page.', function () {
beforeEach(function () {
$state.go('start', { });
$rootScope.$apply();
});
it('Should view page.', function () {
expect($state.current.name).toEqual('start');
});
});
});
Maximum call stack exceeded suggests that something is happening recursively. I'd guess that the state that you are going to "start" is also not authorised, so you get redirected to "start" again, and so on.
You need to make your AuthService.IsAuthorized return true at some point
Ok so it appears to be a bug with ui-router.
Here is a solution
https://github.com/angular-ui/ui-router/issues/178#issuecomment-49156829
$state.go(toState.name, toParams, {notify: false}).then(function() {
$rootScope.$broadcast('$stateChangeSuccess', toState, toParams, fromState, fromParams);
});
The above code will deal with the problem without breaking the browser or unit tests.
Just beware of https://github.com/angular-ui/ui-router/issues/1348 when using this fix.
Use $state.go("main", {}, {notify:false}); for notify to $stateChangeStart event.
$state.go("main", {}, {notify:false});

Resources