How to $watch state change of $stateProvider in AngularJS? - angularjs

I know that I can run:
scope.$watch(someItem, function(){})
But I can't figure out a way to watch over change of $state.$current.name in my application.

It's in the docs: https://github.com/angular-ui/ui-router/wiki#state-change-events
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
// do something
})

This works:
$scope.$watch(function(){
return $state.$current.name
}, function(newVal, oldVal){
//do something with values
})

Related

Angular JS, unable to get handle to rootScope [duplicate]

This question already has answers here:
Cannot get to $rootScope
(3 answers)
Closed 5 years ago.
I am using angular 1.5.x
Below is my routing logic but I am not able to get a handle of the rootScope.
Please can you advise what could be wrong?
UPDATE: I have updated the routing logic as per the answer post below.
I am still not able to hit the controller.
(function() {
'use strict';
angular
.module('icebergApp')
.config(setupRouting);
setupRouting.$inject = ['$stateProvider', '$urlRouterProvider', '$rootScope'];
function setupRouting($stateProvider, $urlRouterProvider, $rootScope) {
$urlRouterProvider.otherwise("/iceberg-ui");
$stateProvider
.state('iceberg.reconlist', {
url: "/iceberg-ui",
templateUrl: "app/iceberg/reconlist/reconlist.view.html",
controller: 'ReconListController as vm'
})
$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
console.log('$stateChangeStart to '+toState.name+'- fired when the transition begins. toState,toParams : \n',toState, toParams);
});
$rootScope.$on('$stateChangeError',function(event, toState, toParams, fromState, fromParams, error){
console.log('$stateChangeError - fired when an error occurs during transition.');
console.log(arguments);
});
$rootScope.$on('$stateChangeSuccess',function(event, toState, toParams, fromState, fromParams){
console.log('$stateChangeSuccess to '+toState.name+'- fired once the state transition is complete.');
});
$rootScope.$on('$viewContentLoading',function(event, viewConfig){
console.log('$viewContentLoading - view begins loading - dom not rendered',viewConfig);
});
$rootScope.$on('$stateNotFound',function(event, unfoundState, fromState, fromParams){
console.log('$stateNotFound '+unfoundState.to+' - fired when a state cannot be found by its name.');
console.log(unfoundState, fromState, fromParams);
});
}
}());
CONTROLLER
(function() {
'use strict';
var myApp = angular.module('iceberg.reconlist', ['ui.router']);
myApp.controller('ReconListController', ReconListController);
ReconListController.$inject = ['ReconListService'];
function ReconListController(ReconListService) {
var vm = this;
}
}());
MODULE
(function() {
'use strict';
angular.module('icebergApp', [
'ui.router',
'iceberg.reconlist'
]);
angular.module('iceberg.reconlist', [
]);
}());
$rootScope is not available in .config(). Only providers are available there. The thing you must do is splitting your code to put the $rootScope part into a .run method.
angular
.module('app')
.config(setupRouting);
setupRouting.$inject = ['$stateProvider', '$urlRouterProvider'];
function setupRouting($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/iceberg-ui");
$stateProvider
.state('iceberg.reconlist', {
url: "/iceberg-ui",
templateUrl: "app/iceberg/reconlist/reconlist.view.html",
controller: 'ReconListController as vm'
})
}
}());
angular.module('app').run(setupRoutingEventListeners);
setupRouting.$inject = ['$rootScope'];
function setupRoutingEventListeners($rootScope) {
$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
console.log('$stateChangeStart to '+toState.name+'- fired when the transition begins. toState,toParams : \n',toState, toParams);
});
$rootScope.$on('$stateChangeError',function(event, toState, toParams, fromState, fromParams, error){
console.log('$stateChangeError - fired when an error occurs during transition.');
console.log(arguments);
});
$rootScope.$on('$stateChangeSuccess',function(event, toState, toParams, fromState, fromParams){
console.log('$stateChangeSuccess to '+toState.name+'- fired once the state transition is complete.');
});
$rootScope.$on('$viewContentLoading',function(event, viewConfig){
console.log('$viewContentLoading - view begins loading - dom not rendered',viewConfig);
});
$rootScope.$on('$stateNotFound',function(event, unfoundState, fromState, fromParams){
console.log('$stateNotFound '+unfoundState.to+' - fired when a state cannot be found by its name.');
console.log(unfoundState, fromState, fromParams);
});
}

Angular app.run possibility of keeping data in app

There is a possibility in app.run I record any information in this case last at $stateParams and write to the $rootScoope?
It would be simple because I pull the server a coming collection mongodb and I just editing it throughout the app.
I want to prevent in all state entries I have to pull the less data.
my app.run in test:
.run(function($rootScope, $state, $stateParams, CLIENTS) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
console.log($stateParams);
CLIENTS.getList({client: client})
.then(function(res){
console.log(res);
});
});
Follow this path:
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
// get Client data
if(!$rootScope.clientSet) {
CLIENTS.getList({client: toParams.client})
.then(function(res){
$rootScope.clientSet = res[0];
});
}
}
https://github.com/angular-ui/ui-router/wiki#state-change-events
You can listen for events so you can refresh data in rootScope.
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){ ... })

Change query param in url using UI-router

Using ui-router how can I accomplish the following URL change? For example, when a user goes to "/page?hello=True" I want the url to change to "/page?status=hello".
$stateProvider.state('page', {
url: '/page/:id?status',
controller: 'MyCtrl as myCtrl',
templateProvider: function($templateCache) {
return $templateCache.get('templates/route.html');
}
});
You can use the stateChangeStart event in the app.run method to listen for state changes into that route, and change anything you want on the params. Something like this, might need to play with toState and toParams to get it right for you...
.run(['$state', '$rootScope', function($state, $rootScope) {
$rootScope.$on('$stateChangeStart', function(e, toState, toParams, fromState, fromParams) {
if (toState.name === 'invitation') {
//change toParams to whatever you want
}
});
});

How to detect state start completion with a combination of $stateChangeStart, $stateChangeSuccess, $state with ui-router for angularjs

I want to impliment a loader image for each state change, and that will be apply to the whole page whenever the state changes. I tried to at least see if they exist, but somehow, I receive not definfed for $stateChangeStart for both when state change start and completed. I wonder what is the best way to do it? Because I want to put that $stateChangeStart as a var for ng-hide directive, so that when every time a state change starts, the loader will show, and (I assume) when $stateChangeSuccess is becoming defined, then its change of state is completed?
Please advice if anything of what I intent to do is wrong and better way to do it. Because I want to build the loader to be directive by itself and its reusable.
Below is the code I try to test these 3 objects.
app.run([
'$rootScope','$location','$state','$stateParams',/*'$templateCache',*/
function (
$rootScope, $location, $state, $stateParams/*, $templateCache*/ ) {
console.log("app run")
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
console.log("state start-------------------------")
console.log($stateChangeStart,"$stateChangeStart ")
console.log($stateChangeSuccess,"$stateChangeSuccess ")
console.log($state);
});
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
console.log("state $stateChangeSuccess-------------------------")
console.log($stateChangeStart,"$stateChangeStart ")
console.log($stateChangeSuccess,"$stateChangeSuccess ")
console.log($state);
});
}]);
Try something like this:
app.run([
'$rootScope','$location','$state','$stateParams',/*'$templateCache',*/
function (
$rootScope, $location, $state, $stateParams/*, $templateCache*/ ) {
console.log("app run")
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
$rootScope.showLoading = true;
});
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
$rootScope.showLoading = false;
});
}]);
and then bind the ng-show to the showLoading property.

ui-router change, when to remove the old html

I've tested this in chrome, and added a break in the $scope.init in Ctrl2
but then when I go to route2 from route1, the chrome debugger stays at $scope.init of Ctrl2, but I see that ctrl1.html is still there.
.state("main.route1", {
url: "/route1",
controller: 'Ctrl1',
templateUrl: 'views/ctrl1.html'
})
.state("main.route2", {
url: "/route2",
controller: 'Ctrl2',
templateUrl: 'views/ctrl2.html'
})
So, how does the ui-router work? Isn't it supposed to go to ctrl2.html, and then execute Ctrl2? Why did it enter Ctrl2 but the ctrl1.html is still displayed?
I'm not sure if it is the same in ng-view, I haven't tested that.
Check js console to make sure you don't have errors in your angular controller
Add following run block to your module to catch state change error
.run(function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
console.log(fromState.name + ' to ' + toState.name);
});
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
alert(error);
event.preventDefault();
});
});

Resources