why $routeChangeSuccess never gets called? - angularjs

I am doing something similar to below on my app but I am just not able to get the routeChangeSuccess event.
var myapp = angular.module('myapp', ["ui.router", "ngRoute"]);
myapp.controller("home.RootController",
function($rootScope, $scope, $location, $route) {
$scope.menus = [{ 'name': 'Home ', 'link': '#/home'}, {'name': 'services', 'link': '#/services'} ]
$scope.$on('$routeChangeSuccess', function(event, current) {
alert('route changed');
});
}
);
myapp.config(
function($stateProvider, $urlRouterProvider, $routeProvider) {
$urlRouterProvider.otherwise("/home");
$stateProvider
.state('home', {
url: "/home",
//template: '<h1>Home Screen</h1>'
templateUrl: "/Client/Views/Home/Home.htm"
})
.state('services', {
url: "/services",
//template: '<h1>Service screen</h1>'
templateUrl: "/Client/Views/Home/service.htm"
});
});
a very simple html as below also fails
<body ng-controller="home.RootController">
<ul class="nav">
<li ng-repeat="menu in menus" "="">
{{menu.name}}
</li>
</ul>
<div ui-view> No data yet!</div>
</body>
but when i click on the link i see that the views are getting updated but the $routeChangeSucces event is never triggered.
is there something i am missing?
Another question I had was is there an event that I can hook on to to know the view is ready so I can start some additional processing, like document.ready().
plnlr but not fully working...
Regards
Kiran

Please, check this wiki: State Change Events. An extract:
$stateChangeSuccess - fired once the state transition is complete.
$scope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){ ... })
So instead of the $routeChangeSuccess use the $stateChangeSuccess.
To get more detailed information about all available events, check the wiki Events. Here you can find that the suitable for you, could be event $viewContentLoaded...

stateChange events are now deprecated and removed, use transitions instead.
$transitions.onSuccess({}, function () {
console.log("state changed");
});

Related

AngularJS - UI Router stateChangeSuccess event not firing

I am using UI Router in my angular app. I am trying to integrate state change events, but they are not firing on state change. Everything else is working fine and there is no error in console. I came across following similar questions, but none of the solution worked for me:
$rootScope.$on("$routeChangeSuccess) or $rootScope.$on("$stateChangeSuccess) does not work when using ui-router(AngularJS)
angular + ui-router: $stateChangeSuccess triggered on state b but not on a.b
Following is my Angular code:
(function() {
angular.module("bootdemo", [
"ngResource",
"ui.router",
"bootdemo.core",
"bootdemo.index"
])
.run(function ($rootScope, $location, $state, $stateParams) {
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
alert("root change success");
})
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options){
alert("root change start");
})
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){
alert("root change error");
})
})
.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
.state('index', {
url: "/",
templateUrl: '/index/templates/welcome.html',
controller: 'IndexController as vm'
})
.state('login', {
url: "/login",
templateUrl: '/index/templates/login.html',
controller: 'LoginController as ctrl'
})
.state('home', {
url: "/home",
templateUrl: '/index/templates/home.html',
controller: 'HomeController as ctrl'
})
});
}());
Left with no clue. I am not sure what I am missing.
StateChange events has been deprecated for ui.router >= 1.0
for the new ui.router use the following
StateChangeSuccess
$transitions.onSuccess({}, function() {
console.log("statechange success");
});
StateChangeStart
$transitions.onStart({}, function(trans) {
console.log("statechange start");
});
Check this migration guide for more information
If you are using the new ui-router (v1.0.0), the $stateChange* events will not work. You must use $transitions.on* hooks from now on.
You can read here.
https://ui-router.github.io/docs/latest/modules/ng1_state_events.html
https://github.com/angular-ui/ui-router/issues/2720
$state events are deprecated for angular version > 1.0.0.
now onward for change event we have to use $transitions
refer $transitions from here

angularJS $stateProvider : How to unit test different views in UI-Router?

How can I unit test different views for the below scenario
.state('app.sr.product.upload', {
name: 'upload',
url: '/upload',
data: {
tags: [],
userCommunities: []
},
views: {
"productView#app.sr.product": {
templateUrl: 'views/upload/upload.html',
controller: 'UploadCtrl',
controllerAs: 'ul'
},
"tags#app.sr.product.upload": {
templateUrl: 'views/tags/tags.html',
controller: 'TagsCtrl',
controllerAs: 'vm'
},
"UserCommunityPanel#app.sr.product.upload": {
templateUrl: 'views/user-community/user-community.html',
controller: 'UserCommunityCtrl',
controllerAs: 'ul'
},
}
})
If my view is tags#app.sr.product.upload then how can I test that
my controller is TagsCtrl, my controllerAs value is vm etc??
How can I unit test if my state is app.sr.product.upload then
data.tags=[], data.userCommunities=[] etc.
I searched for lot of docs and tutorials but didnt get it .
Any help is appreciable.
Thanks
Try this on for size. I'm assuming you would be using jasmine for your tests, but the concept is the same for any testing framework.
When you run your test, first subscribe to the '$stateChangeSuccess' event and then navigate to that state. Once the event fires, check the toState values to see if they are what you expect them to be.
You can run the snippet to see the tests in action.
//write a unit test
describe('state changes', function() {
beforeEach(module('app'));
var $rootScope, $state;
beforeEach(inject(function(_$rootScope_, _$state_) {
// The injector unwraps the underscores (_) from around the parameter names when matching
$rootScope = _$rootScope_;
$state = _$state_;
}));
it('loads page 1', function(done) {
//wait for the state to change, then make sure we changed to the correct state
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
expect(toState.controller).toEqual('Controller1');
done();
});
//navigate to the state
$state.go('state1');
//start a digest cycle so ui-router will navigate
$rootScope.$apply();
});
it('loads page 2', function(done) {
//wait for the state to change, then make sure we changed to the correct state
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
expect(toState.controller).toEqual('Controller2');
done();
});
//navigate to the state
$state.go('state2');
//start a digest cycle so ui-router will navigate
$rootScope.$apply();
});
it('loads page 3', function(done) {
//wait for the state to change, then make sure we changed to the correct state
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
expect(toState.controller).toEqual('Controller3');
done();
});
//navigate to the state
$state.go('state3');
//start a digest cycle so ui-router will navigate
$rootScope.$apply();
});
});
//set up some dummy controllers and some dummy states
angular.module('app', ['ui.router']).controller('Controller1', function() {
this.message = 'Page 1';
}).controller('Controller2', function() {
this.message = 'Page 2';
}).controller('Controller3', function() {
this.message = 'Page 3';
}).config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/state1");
$stateProvider.state('state1', {
url: "/state1",
controller: 'Controller1',
controllerAs: 'vm',
template: '<h1>{{vm.message}}</h1>'
}).state('state2', {
url: "/state2",
controller: 'Controller2',
controllerAs: 'vm',
template: '<h2>{{vm.message}}</h2>'
}).state('state3', {
url: "/state3",
controller: 'Controller3',
controllerAs: 'vm',
template: '<h3>{{vm.message}}</h3>'
});
});
h1 {
color: red;
}
h2 {
color: blue;
}
h3 {
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="
https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<link rel="stylesheet" type="text/css" href="http://jasmine.github.io/2.0/lib/jasmine.css">
<script src="http://jasmine.github.io/2.0/lib/jasmine.js"></script>
<script src="http://jasmine.github.io/2.0/lib/jasmine-html.js"></script>
<script src="http://jasmine.github.io/2.0/lib/boot.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-mocks.js"></script>
<div ng-app="app">
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
<a ui-sref="state3">State 3</a>
<div ui-view></div>
</div>
If I'm not wrong, I think we missed the point of the initial question, which was
if my view is tags#app.sr.product.upload then how can I test that my
controller is TagsCtrl, my controllerAs value is vm etc??
and
How can I unit test if my state is app.sr.product.upload then
data.tags=[], data.userCommunities=[] etc.
Here's how you can test these :
var $rootScope, $state, $injector, state;
beforeEach(inject(function(_$rootScope_, _$state_){
$rootScope = _$rootScope_;
$state = _$state_;
state = $state.get('app.sr.product.upload');
}));
it('should have the correct data parameters', function () {
expect(state.data.tags).toEqual('');
expect(state.data.userCommunities).toEqual('');
});
it('should render the dashboard views with the right Controllers', function () {
var product = state.views['productView#app.sr.product'];
var tags= state.views['tags#app.sr.product.upload'];
var userCommunity = state.views['UserCommunityPanel#app.sr.product.upload'];
expect(product.templateUrl).toEqual('views/upload/upload.html');
expect(product.controller).toEqual('UploadCtrl');
expect(product.controllerAs).toEqual('ul');
// etc...
});
Also, in newer angular versions, you can just declare your controller like so:
controller: 'UploadCtrl as vm'
It's not something I would normally unit test. UI-Router itself is well covered by tests.
You'd do better with e2e (end-to-end) tests with Protractor. You simulate a click on a link, you expect url to be this, use expect number of elements in a list to be that etc.
But if you really need it:
locate root element of each view (f.e. by adding a specific class and using selectors)
you should be able to access scope
and controller via
angular.element
wrapper methods

ui.router not being loaded/executed

I am new to ui.router and trying to get it working on a new application. The code is behaving like the state provider is either not loaded or it does not see the ui-view DOM element. I know the dependency is loaded properly (or least it isn't throwing any errors) and I have been over a ton of blog posts but everything looks right. I have a couple 'made it here' style messages but I never see them in the console.
The plunk below shows the following paragraph is not an issue. I am leaving the paragraph here for posterity but do not see a strike-through option in SO formatting...
I should also point out that this will be a SharePoint provider hosted app so there is a ton of query string garbage that I suspect is mucking things up. Unfortunately I can't get rid of them.
---Edit---
I made a plunk
/---Edit---
Here is my module:
var app = angular.module('myApp', ['ui.router']).
config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/',
templateUrl: 'partials/admin.html',
onEnter: function ($stateParams) {
console.log("Entered Admin route");
}
//controller: 'myController'
})
.state('sitebinding', {
url: '/sitebinding',
templateUrl: 'sitebinding.html'
})
.state('scrum', {
url: '/scrum',
templateUrl: 'scrum.html'
});
$urlRouterProvider.otherwise('/');
}
]);
angular.module('myApp',[
'myApp.controllers'
]);
Here is the controller:
angular.module('myApp.controllers', []).
controller('myController', function ($scope) {
$scope.models = {
helloAngular: 'I work!'
};
$scope.$on('$stateChangeStart', function (evt, toState, toParams, fromState, fromParams) {
console.log('In state change start');
})
});
And here is the relevant bits from the index.cshtml.
<div data-ng-app="myApp">
<div>
<div class="container">
<div ui-view="app"></div>
</div>
</div>
</div>
Not sure what your trying to do here in your plunkr. You have scrum.html in your route setup but it does not exist in your file tree. Are you just trying to get admin.html to show? Are you trying to fire this view on a click?

AngularJS ui-router: receive an event every time a user goes to a state

I need to receive an event in AngularJS ui-router when the user goes to a state, even when they go to that state twice in a row (i.e. clicking the same url twice). For example, in this plunk, you will only be notified the first time you click on the url or when you click on a different url. If you click on the same url twice, you won't see the alert message.
I need the event to be fired every time the user clicks on a link, regardless. Couldn't find a ui-router event, any ideas?
HTML:
Populate page 1
Populate page 2
<br/><br/>
<div ui-view></div>
Javascript:
angular.module("app", ['ui.router']);
function MyCtrl($scope) {}
angular.module("app").
config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('page1', {
templateUrl: 'page1.html',
controller: function($scope) {
$scope.$on("$viewContentLoaded", function(){
alert("$viewContentLoaded - 1");
});
}
})
.state('page2', {
templateUrl: 'page2.html',
controller: function($scope) {
$scope.$on("$viewContentLoaded", function(){
alert("$viewContentLoaded - 2");
});
}
});
});
Here you go:
myAppModule.controller('SomeBaseController', function($scope) {
// called when any state changes.
$scope.$on('$stateChangeStart', function(event, toState, toParams) {
// call event.preventDefault() to prevent from transition.
});
});
Reference: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state
Plunkr: http://plnkr.co/edit/6kimGOWlO5LvU5bTcQuH?p=preview
Hope this helps!

How to trigger UI-Router View Load events?

Testing ui-router for the fist time but testing the Events at the moment and I can't seem to understand how to trigger $viewContentLoaded or Loading. Although, I've got stageChangeSuccess, etc working! I just pushed everything to http://punkbit.com/space_competition/ but also added some code here. I expected to trigger the events when a new view is loaded to ui-view. But I guess I'm missing something here!
<div class="pure-g">
<div class="pure-u-1" ui-view>
</div>
</div>
<!-- s: template partials -->
<script type="text/ng-template" id="menu.html">
<div class="pure-menu pure-menu-open pure-menu-horizontal">
<ul>
<li>home</li>
<li class="pure-menu-selected">like_gate</li>
<li>terms_and_conditions</li>
<li>enter_competition</li>
</ul>
</div>
</script>
<script type="text/ng-template" id="home.html">
<p>home.html template! fbLike is {{fbLike}}</p>
</script>
<script type="text/ng-template" id="enter_competition.html">
<p>enter_competition.html template!</p>
</script>
<script type="text/ng-template" id="like_gate.html">
<p>like.html template!</p>
</script>
<script type="text/ng-template" id="terms_and_conditions.html">
<p>terms_and_conditions.html template!</p>
</script>
<!-- e: template partials -->
main.js
angular.module("space_competition", ['ui.router'])
.config(function($stateProvider, $urlRouterProvider, $locationProvider){
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home.html',
controller: 'homeCtrl',
resolve: {
fb_like: 'fbLike'
}
})
.state('enter_competition', {
url: '/enter_competition',
templateUrl: 'enter_competition.html',
controller: 'enterCompetitionCtrl',
resolve: {
fb_like: 'fbLike'
}
})
.state('like_gate', {
url: '/like_gate',
templateUrl: 'like_gate.html',
controller: 'likeGateCtrl'
})
.state('terms_and_conditions', {
url: '/terms_and_conditions',
templateUrl: 'terms_and_conditions.html',
controller: 'termsAndConditionsCtrl'
});
$urlRouterProvider.otherwise("/home");
//$locationProvider.hashPrefix('!');
})
.run(function($rootScope){
$rootScope
.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
console.log("State Change: transition begins!");
});
$rootScope
.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){
console.log("State Change: State change success!");
});
$rootScope
.$on('$stateChangeError',
function(event, toState, toParams, fromState, fromParams){
console.log("State Change: Error!");
});
$rootScope
.$on('$stateNotFound',
function(event, toState, toParams, fromState, fromParams){
console.log("State Change: State not found!");
});
$rootScope
.$on('$viewContentLoading',
function(event, viewConfig){
console.log("View Load: the view is loaded, and DOM rendered!");
});
$rootScope
.$on('$viewcontentLoaded',
function(event, viewConfig){
console.log("View Load: the view is loaded, and DOM rendered!");
});
})
.controller('homeCtrl', function($scope, fbLike){
$scope.fbLike = fbLike.liked();
})
.controller('enterCompetitionCtrl', function($scope, fbLike){
fbLike.liked();
})
.controller('likeGateCtrl', function($scope){
})
.controller('termsAndConditionsCtrl', function($scope){
})
.factory('fbLike', function($http, $q){
return {
liked: function(){
return true;
}
};
});
Anyone experienced could have a look please ?
Thanks : D
it looks like you have $viewcontentLoaded instead of $viewContentLoaded. did you forget to camel-case-capitalize the C?
The $viewContentLoading event is now correctly firing with release 0.2.11: fix(state): allow view content loading broadcast

Resources