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

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

Related

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

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>

AngularJS, string not interpolating $routeParams values

I am trying to build a link using routeParams of the route angularJs class. which works pretty well but for some reason it doesn't interpolate my strings.
I have tried the following:
{{username}} as in the controller i set $scope.username = $routeParams.username;
{{ Repo.username }} as the controller is called RepoController.
however both had no result except printing it as a string literal on the screen.my code is as below
App.js
(function() {
var app = angular.module("githubViewer", ["ngRoute"])
app.config(function($routeProvider) {
$routeProvider
.when("/main", {
templateUrl: "main.html",
controller: "MainController"
})
.when("/user/:username", {
templateUrl: "user.html",
controller: "UserController"
})
.when("/repo/:username/:reponame", {
templateUrl: "repo.html",
controller: "RepoController"
})
.otherwise({
redirectTo: "/main"
})
});
}());
RepoController.js
(function() {
var app = angular.module("githubViewer")
var RepoController = function($scope, github, $routeParams) {
$scope.username = $routeParams.username;
$scope.reponame = $routeParams.reponame;
app.controller("RepoController", ["$scope", "github", "$routeParams", RepoController]);
}());
Repo.html
<section>
{{ username }}
<br />
{{ repo.name }}
</section>
There is a plunker available:
https://plnkr.co/edit/oGJJOUfCqW8G7OAXxXGa?p=preview
thanks a lot for any help. Cheers!
There are a couple of syntactic and semantic issues in the Plunkr that may be affecting your actual code.
You have a syntax error in the RepoController.js -- you do not close the RepoController function declaration with }
You are not including <script src=RepoController.js> in index.html
$scope.repo is not an object with a name property. In your template, use reponame instead or you could do $scope.repo = {name: $routeParams.reponame}

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 '#'

Does AngularJS have dynamic routing?

Does angular support dynamic routing at all?
Maybe some trick like this:
$routeProvider.when('/:ctrl/:action',
getRoute($routeParams.ctrl,$routeParams.action))
function getRoute(ctrl, action){
return {
templateUrl: ctrl+"-"+action+".html"
controller: 'myCtrl'
}
}
Please help me, I need to get templateUrl based out of routeParams
This is a late answer but I came across this problem myself, but it turns out that the solution by Dan conflicts with ngAnimate classes on the ngView directive, and the view is shown but the ng-leave animation will immediately be applied and hide the view opened with his dynamic routing.
I found the perfect solution here, and it's available in 1.1.5 +
In the $routeProvider, the templateUrl value can be a function, and is passed the route parameters:
app.config(function ($routeProvider) {
$routeProvider
.when('/:page', {
templateUrl: function(routeParams){
return '/partials/'+routeParams.page+'.html';
}
})
});
Though the controller can't be given as a function so my solution is to give it in the template html as per usual with ng-controller="HomeCtrl".
Using this solution we can route by convention in Angular.
I hope this helps others who weren't keen on manually adding every route to the routeProvider.
You want to bring it down to the controller level.
In this example, I am overriding entire pages as well as partials by subdomain:
app.js
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/', {
template: 'home'
});
$routeProvider.when('/contact', {
template: 'contact'
});
$routeProvider.otherwise({redirectTo: '/'});
}])
controllers.js
controller('AppController', ['$scope','Views', function($scope, Views) {
$scope.$on("$routeChangeSuccess",function( $currentRoute, $previousRoute ){
$scope.page = Views.returnView();
});
$scope.returnView = function(partial){
return Views.returnView(partial);
}
}])
services.js
factory('Views', function($location,$route,$routeParams,objExistsFilter) {
var viewsService = {};
var views = {
subdomain1:{
'home':'/views/subdomain1/home.html'
},
subdomain2:{
},
'global.header':'/views/global.header.html',
'global.footer':'/views/global.footer.html',
'home':'/views/home.html',
'home.carousel':'/views/home.carousel.html',
'contact':'/views/contact.html',
};
viewsService.returnView = function(partial) {
var y = (typeof partial === 'undefined')?$route.current.template:partial;
var x = $location.host().split(".");
return (x.length>2)?(objExistsFilter(views[x[0]][y]))?views[x[0]][y]:views[y]:views[y];
};
viewsService.returnViews = function() {
return views;
};
return viewsService;
}).
filters.js
filter('objExists', function () {
return function (property) {
try {
return property;
} catch (err) {
return null
}
};
});
index.html
<!doctype html>
<html lang="en" ng-controller="AppController">
<body>
<ng-include src="returnView('global.header')"></ng-include>
<ng-include src="page"></ng-include>
<ng-include src="returnView('global.footer')"></ng-include>
</body>
</html>

All variables in $scope undefined in Angular.js

I have a very simple website which uses Angular.js to display its content. I started learning it 2 days ago, and following the official tutorial gave no issues at all.
This is my js file:
var Site = angular.module('Website', []);
Site.config(function ($routeProvider) {
$routeProvider
.when('/home', {templateUrl: 'parts/home.html', controller: 'RouteController'})
.when('/who', {templateUrl: 'parts/who.html', controller: 'RouteController'})
.when('/what', {templateUrl: 'parts/what.html', controller: 'RouteController'})
.when('/where', {templateUrl: 'parts/where.html', controller: 'RouteController'})
.otherwise({redirectTo: '/home'});
});
function AppController ($scope, $rootScope, $http) {
// Set the slug for menu active class
$scope.$on('routeLoaded', function (event, args) {
console.log(args);
$scope.slug = args.slug;
});
}
function RouteController ($scope, $rootScope, $routeParams) {
// Getting the slug from $routeParams
var slug = $routeParams.slug;
var pages = {
"home": {
"title": "Samuele Mattiuzzo",
},
"who": {
"title": "All you'll get, won't blog"
},
"what": {
"title": "Shenanigans about this website"
},
"where": {
"title": "Where can you find me on the net?"
}
};
$scope.$emit('routeLoaded', {slug: slug});
$scope.page = pages[slug];
}
As you can see, it's very simple, it just need to return a page title based on the page slug. In the template (where I load my app with <body ng-controller="AppController">), inside the <ng-view> directive I have one of those partial templates loaded (which is currently working and displaying static content) but I cannot see the content of {{page.title}}.
I have Batarang enabled on my browser and I'm testing my website with web-server.js, but I've read that Batarang has some issues with variables and scopes and always returns undefined, so that's why I added that console.log statement. Doesn't matter what I try to print (args, slug or page, obviously in different parts of the js), it's always undefined.
What am I exactly doing wrong here? Thanks all
None of your controllers are being associated with your "Site".
I believe if you change your free functions to be associated with Site this should get you on the right track. Also, you can simplify your code slightly since the information you're looking for is contained in the $location and not $routeParams.
Site.controller("RouteController", function($scope, $location) {
var slug = $location.path();
var pages = {
"/home": {
"title": "Samuele Mattiuzzo",
},
"/who": {
"title": "All you'll get, won't blog"
},
"/what": {
"title": "Shenanigans about this website"
},
"/where": {
"title": "Where can you find me on the net?"
}
};
$scope.page = pages[slug];
});
Additionally, in your AppController you can watch for $routeChangeSuccess instead of notifying on a location change from your RouteController:
Site.controller("AppController", function($rootScope) {
$rootScope.$on("$routeChangeSuccess", function() { \\do something }
});

Resources