Getting a "Transition Rejection" when using ui router with template url - angularjs

I have a basic angularjs (1.8.2) application with the latest version of ui router (1.0.29).
The application will load and work fine but I have noticed in the console I get the following errors when I initially go to a state (using the ui-sref route) with a template url:
​Transition Rejection($id: 0 type: 2, message: The transition has been superseded by a different transition, detail: Transition#2( 'home'{} -> 'page2'{} ))
It only happens the first time a user goes to a state with a template url, after that there are no more errors and the application continues to work.
Demo Here
All the information I have found online just says that I have a configuration error with ui router but all the documentation I have found shows that this should work without error.
Any help is appreciated, thanks.
var app = angular.module('plunker', ['ui.router', 'editor']);
// routing configuration
app.config(['$urlRouterProvider', '$stateProvider', function ($urlRouterProvider, $stateProvider) {
// default route
$urlRouterProvider.otherwise('/');
// available states
var states = [
{
name: 'home',
url: '/',
template: '<div><h3>HOME PAGE</h3></div>'
},
{
name: 'page2',
url: '/page2',
controller: 'page2Ctrl',
templateUrl: 'page2.html',
},
{
name: 'page3',
url: '/page3',
controller: 'page3Ctrl',
templateUrl: 'page3.html',
}
];
// Loop over the state definitions and register them
states.forEach(function (state) {
$stateProvider.state(state);
});
}]);
app.controller('mainCtrl', function($scope) {
$scope.content = 'World';
});
app.controller('page2Ctrl', function($scope) {
$scope.hasLoaded = true;
});
app.controller('page3Ctrl', function($scope) {
$scope.hasLoaded = true;
});

Error caused because there are 2 ui-sref for each state. Remove the one from li element and it works fine:
<li role="presentation" ui-sref-active="active">
<a ui-sref="home" ui-sref-opts="{reload: true, inherit: false}">
Home
</a>
</li>

Related

Browser back button angular ui router

I want to get working back button of the browser with angular 1.4.10 ui-router.
This is sample code of my app.js
var myApp = angular.module("myApp",[ "ui.router", "AppCtrls"]);
myApp.config(function ($stateProvider, $urlRouterProvider, $locationProvider){
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
$stateProvider.state("state1", {
url: "",
template: "<p>State 1</p>",
controller: "Ctrl1"
}).state("state2", {
url: "",
template: "<p>State 2</p>",
controller: "Ctrl2"
});
});
var ctrls = angular.module("AppCtrls", []);
ctrls.controller( "Ctrl1", function($scope) {
console.log("Ctrl1 loaded.");
});
ctrls.controller( "Ctrl2", function($scope) {
console.log("Ctrl2 loaded.");
});
When I am giving URL to each state back button works well but when I have not given any URL to each state back button is not working.
Is there any workaround to get back button working without having URL of state?

Highlighted active tab does not switch when clicked. Using Angularjs ui-router ui-bootstrap tabs

I am using Angularjs ui-router ui-bootstrap tabs.
It works on http://plnkr.co/edit/EYLsPRlxEXQP4HsXuPKK?p=info but does not work on my website. The active tabs does not get highlighted when clicked. The correct content loads though.
var app = angular.module('Plunker', ['ui.router', 'ui.bootstrap'])
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tab1', {
url: '/tabpage1',
templateUrl: 'tab1.html',
controller:'tabsController'
})
.state('tab2', {
url: '/tabpage2',
templateUrl: 'tab2.html',
controller:'tabsController'
})
.state('tab3', {
url: '/tabpage3',
templateUrl: 'tab3.html',
controller:'tabsController'
})
$urlRouterProvider.otherwise('/');
});
app.controller('tabsController',['$scope','$state',function($scope, $state){
$scope.tabs = [
{ title: 'Announcements', route:'tab1', active:false},
{ title: 'Course Info', route:'tab2', active:true},
{ title: "Timetable", route: "tab3", active: false },
];
}]);
Can anybody kindly advise?
Thank you.

Angular ngRoute - Cannot GET page if enter url manually

I'm a beginner to AngularJS and have the following question. I'm playing with ngRoute module and this is my code so far:
html:
<nav ng-controller="navController as nav">
<ul>
<li ng-repeat="item in navItems">
{{ item.name }}
</li>
</ul>
</nav>
<div id="main">
<div ng-view></div>
</div>
app.js
(function(window) {
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl : 'pages/home.html',
controller : 'mainController'
})
.when('/contact', {
templateUrl : 'pages/contact.html',
controller : 'contactController'
});
if (window.history && window.history.pushState) {
$locationProvider.html5Mode(true);
}
}]);
app.controller('mainController', ['$scope', function($scope) {
$scope.message = 'Hello from home page';
}]);
app.controller('contactController', ['$scope', function($scope) {
$scope.message = 'Hello from contact page';
}]);
app.controller('navController', ['$scope', function($scope) {
$scope.navItems = [
{ name: 'Home', url: '/' },
{ name: 'Contact', url: '/contact' }
];
}]);
})(window);
And it works fine. Angular renders menu, and when I click on the link it shows me desired page. But except in the following case. When it displays the homepage (url: http://localhost:3000) and i manually add to the url address "/contact" then I'm getting blank page with error "Cannot GET /contact". Could someone explain me why this is happening and how can I fix it? I would appreciate any help. Thanks.
In fact you need the # (hashtag) for non HTML5 browsers.
Otherwise they will just do an HTTP call to the server at the mentioned href. The # is an old browser shortcircuit which doesn't fire the request, which allows many js frameworks to build their own clientside rerouting on top of that.
You can use $locationProvider.html5Mode(true) to tell angular to use HTML5 strategy if available.
Here the list of browser that support HTML5 strategy: http://caniuse.com/#feat=history
Source: AngularJS routing without the hash '#'

Why to use abstract keyword in angular js?

I recently started with Ionic framework but to begin with Ionic Angular.js is pre-requisite. Can any one please tell me why do we use abstract keyword in nested ui-router. I was unable to find a good tutorial on that.
Please tell me what is the significance/advantages of abstract in angular.js.
Here is the code that I am unable to understand
var app = angular.module('ionicApp', ['ionic'])
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/todos')
$stateProvider.state('app', {
abstract: true,
templateUrl: 'main.html'
})
$stateProvider.state('app.todos', {
abstract: true,
url: '/todos',
views: {
todos: {
template: '<ion-nav-view></ion-nav-view>'
}
}
})
All right I will just post some of my experience using ionic.
- Ui router parent/child scope inheritance
This is not specific to ionic. Sometimes if you want to share some common function in relation to views, by using scope inheritance, you can consolidate default/share function in the parent, or setup default states in your view, or inherit resolved dependencies.
$stateProvider.state('app', {
abstract: true,
templateUrl: 'main.html',
resolve: {
commonMeta: ["$stateParams","$http", function($stateParams, $http) {
return $http.get("/commonMeta/" + $stateParams.id);
}]
},
controller: ["$scope", function($scope) {
// controller should be in a separate file
$scope.data = {};
$scope.state = {};
$scope.display = function() {
// common logic for page display
};
$scope.restoreCustomerPreference = function() {
// restore customer preference from say localstorage
};
$scope.init = function() {
// 'this' will be the child $scope
this.state = {
error: false
};
this.restoreCustomerPreference();
};
}],
});
$stateProvider.state('app.dashboard', {
url: '/dashboard',
views: {
todos: {
template: '<ion-nav-view></ion-nav-view>'
}
},
resolve: {
data: ["$http", function($http) {
return $http.get("/getDashboard/");
}]
},
controller: ["$scope","commonMeta","data" function($scope,commonMeta,data) {
// controller should be in a separate file
$scope.data = data;
$scope.display = function() {
// override the display logic
$
};
$scope.init();
}]
});
$stateProvider.state('app.todos', {
url: '/todos',
views: {
todos: {
template: '<ion-nav-view></ion-nav-view>'
}
},
resolve: {
data: ["$http", function($stateParams, $http) {
return $http.get("/getTodos/");
}]
},
controller: ["$scope", function($scope) {
// controller should be in a separate file
$scope.data = data;
$scope.someFn = function() {
// some function
};
$scope.init();
}]
});
Try to use controller: ["$scope", function($scope) { }] this form of dependencies injection, so your codes do not break when minified.
- ionic-slide-box
Using ionic-slide-box can develop app that user can slide left and right to get to next page, similar to facebook, by using a simple directive to fetch your template.
angular.module("directives",[])
.directive("slideItem", ["$http","$templateCache","$compile",function($http,$templateCache,$compile) {
return {
replace: false,
restrict: "EA",
scope: {
template: "#"
},
link: function(scope, iElement, iAttrs, controller) {
var events = scope.events();
$http.get(iAttrs.template, {cache: $templateCache})
.success(function(result) {
iElement.replaceWith($compile(result)(scope));
});
}
};
}]);
The template file can be hardcoded one:
<ion-view>
<ion-slide-box show-pager="false">
<ion-slide>
<slide-item template="templates/dashboard.html"></slide-item>
</ion-slide>
<ion-slide>
<slide-item template="templates/todos.html"></slide-item>
</ion-slide>
<ion-slide>
<slide-item template="templates/sumary.html"></slide-item>
</ion-slide>
</ion-slide-box>
</ion-view>
or using ng-repeat:
<ion-view>
<ion-slide-box show-pager="false">
<ion-slide ng-repeat="o in slides">
<slide-item template="templates/{{o.template}}.html" ></slide-item>
</ion-slide>
</ion-slide-box>
</ion-view>
Weinre is a debug tool that you must have, it can debug even
when your app is installed to a real device. without that, when your
app start with a blank screen you just don't know what to look for.
ngCordova is a wrapper for cordova function develop by ionic
too.
Android device can be test easily, TestFlight is good for ios
testing.
When using nested states an abstract state can have child states but cannot be activated itself.
Reference:
Nested States & Nested Views

Angular.js: Adding a simple route to a demo app?

I am building a really simple demo Angular application, to see how it compares to Backbone, and I've got stuck when it comes to routing, although I've read the routing tutorial.
I'd like the route in my demo app to update whenever the <select> element changes, to /LHR or /SFO or whatever the new value of the select is (and presumably /#LHR etc in browsers without the History API).
I'd also like the router to handle the initial path when the page loads, and set up the default value of the <select> option.
Here is my HTML - I only have one template:
<html ng-app="angularApp">
[...]
<body ng-controller="AppCtrl">
<select ng-model="airport" ng-options="item.value as item.name for item in airportOptions" ng-change='newAirport(airport)'></select>
<p>Current value: {{airport}}</p>
</body></html>
And here is my JS in full:
var angularApp = angular.module('angularApp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/:airportID', {templateUrl: 'angular.html', controller: AppCtrl}).
otherwise({redirectTo: '/'});
}]);
angularApp.controller('AppCtrl', function AppCtrl ($scope, $http, $routeParams) {
$scope.airportOptions = [
{ name: 'London Heathrow', value: 'LHR' },
{ name: 'San Francisco International', value: 'SFO' },
{ name: 'Paris Charles de Gaulle', value: 'CDG' }
];
$scope.airport = $scope.airportOptions[0].value; // Or the route if provided
$scope.newAirport = function(newAirport) {
console.log('newAirport', newAirport);
};
});
I'm not at all sure that I've set up the route provider correctly, and currently it's giving me Uncaught ReferenceError: AppCtrl is not defined from angularApp. What am I doing wrong?
UPDATE: I fixed the ReferenceError by putting AppCtrl in quotes, thanks commenter. Now my problem is that $routeParams is empty when I try to navigate to /#LHR. How can I get the route parameter?
UPDATE 2: Got the route working - feels a bit hacky though. Am I doing it right?
var angularApp = angular.module('angularApp', []);
angularApp.config(function($routeProvider, $locationProvider) {
$routeProvider.
when('/:airportID', {templateUrl: 'angular.html', controller: "AppCtrl"}).
otherwise({redirectTo: '/'});
});
angularApp.controller('AppCtrl', function AppCtrl ($scope, $routeParams, $location) {
$scope.airportOptions = [
{ name: 'London Heathrow', value: 'LHR' },
{ name: 'San Francisco International', value: 'SFO' },
{ name: 'Paris Charles de Gaulle', value: 'CDG' }
];
var starting_scope = null;
($location.path()) ? starting_scope = $location.path().substr(1) : starting_scope = $scope.airportOptions[0].value;
$scope.airport = starting_scope;
$scope.newLeague = function(newLeague) {
$location.path("/" + newLeague);
}

Resources