How to trigger UI-Router View Load events? - angularjs

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

Related

ui-router $stateChangeState event cannot trigger

i want to load an animate when routechange.
why nothing in console.
html
<body ng-app="app" ng-controller="ctrl">
<a ui-sref="home">home</a>
<a ui-sref="route">route</a>
<ui-view></ui-view>
<script src="//cdn.bootcss.com/angular.js/1.5.5/angular.min.js"></script>
<script src="//cdn.bootcss.com/angular-ui-router/1.0.0-rc.1/angular-ui-router.min.js"></script>
js
var app = angular.module('app',['ui.router']);
app.config(function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home',{
url:'/home',
template:'<div>home</div>'
})
.state('route',{
url:'/route',
template:'<div>route</div>'
})
})
app.controller('ctrl',function($scope){
});
app.run(function($rootScope,$state){
// $rootScope.$state = $state;
$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
console.log(111); //why cannot?
// load.onLoading(); //loading animate..
})
});
</script>
</body>
i want to load an animate when routechange.
why nothing in console.
From angular-ui-router docs:
State Change Events
NOTE: State change events are deprecated, DISABLED and replaced by
Transition Hooks as of version 1.0 (details)
And to migrate from legacy to the most recent angular-ui-router version:
// Legacy example
app.run(function($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams) {
// some code
});
});
// Migrate to: UI-Router 1.0 Transition Hook
app.run(function($transitions) {
$transitions.onStart({ }, function(trans) {
// some code
});
});
Source here
Its better to use ng-animate module to animate page route. You can see the docs here. You can also check for this tutorial. Tutorial

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

Using global template variable in controllers angularjs

I am trying to add viewTitle to base view or root web app page, e.g.
Root Page
<div ng-app="app">
{{viewTitle}}
<div ui-view=""></div>
</div>
can I change viewTitle in controllers ?
Controller-1
var myApp = angular.module(app, []);
myApp.controller('ChildController', ['$scope', function($scope) {
// how to update viewTitle here ?
}]);
One solution may be this:
If you use ui-router you can add a title in state: (I use this to translate the title)
.state('login', {
url: '/login',
controller: 'AdminLoginController',
templateUrl: 'app/admin/views/login.html',
title: {
'es': 'Iniciar sesión',
'en': 'Login',
'de': 'Einloggen'
}
})
.state('panelAdmin', {
url: '',
controller: 'AdminHomeController',
templateUrl: 'app/admin/views/panelAdmin.html',
title: {
'es': 'Panel de administración',
'en': 'Control panel',
'de': 'Führungspanel'
}
})
And in $stateChangeStart reload the title:
$rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
if (toState.title) {
$rootScope.title = toState.title[$rootScope.cultureLang];
}
});
In index.html:
<title>{{title}}</title>
I think we can use $rootScope for this purpose. Please see below.
html template
<body ng-app="myApp" >
{{viewTitle}}
<div ui-view=""></div>
</div>
</body>
js file
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/',
template: '<h1>From nested view </h1>',
controller: function($rootScope)
{
$rootScope.viewTitle = "home";
}
});
});
Hope it helps

why $routeChangeSuccess never gets called?

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");
});

Resources