Angular $routeParams is blank - angularjs

I have a really simple Angular app that I've distilled to the following:
var napp = angular.module('Napp',['ngResource']);
var CompanyCtrl = function($scope, $routeParams, $location, $resource) {
console.log($routeParams);
};
napp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/company/edit/:id',
{templateUrl: '/partials/edit', controller: 'CompanyCtrl'}
);
}]);
and the HTML:
<div ng-controller="CompanyCtrl"></div>
When I log $routeParams, it comes up blank. When I use .otherwise(), it will load whatever I've specified there. Any idea what I'm missing?

You have a couple of errors:
You've specified the controller in two places, both in the view (<div ng-controller="CompanyCtrl"></div>) and in $routeProvider (.when('/company/edit/:id', {templateUrl: '/partials/edit', controller: 'CompanyCtrl'}). I'd remove the one in the view.
You have to register the controller in the module when specifying it in the $routeProvider (you should really do this anyway, it's better to avoid global controllers). Do napp.controller('CompanyCtrl', function ... instead of var CompanyCtrl = function ....
You need to specify a ng-view when you're using the $route service (not sure if you're doing this or not)
The new code:
var napp = angular.module('Napp', ['ngResource']);
napp.controller('CompanyCtrl', function ($scope, $routeParams, $location, $resource) {
console.log($routeParams);
});
napp.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/company/edit/:id',
{templateUrl: '/partials/edit', controller: 'CompanyCtrl'}
);
}]);
The template (/parials/edit)
<div> ... </div>
And the app (index.html or something)
... <body> <div ng-view></div> </body>
I've created a working plunker example: http://plnkr.co/edit/PQXke2d1IEJfh2BKNE23?p=preview

First of all try this with
$locationProvider.html5Mode(true);
That should fix your starting code. Then adjust your code to support non-pushState browsers.
Hope this helps!

Not sure if this helps, but I just came across this issue myself, and found that I couldn't log the route params until I had something bound to them.
So,
Router:
var myApp = angular.module('myApp', []);
myApp.config(function($routeProvider){
$routeProvider.when('/projects/:id',
{templateUrl: '/views/projects/show.html', controller: 'ProjectCtrl'}
);
});
Controller:
myApp.controller('ProjectCtrl', function($scope, $routeParams){
$scope.id = $routeParams.id;
console.log('test');
});
View:
<h1>{{ id }}</h1>
When I removed the '{{id}}' from the view, nothing was logged and $routeParams was empty, at least at the time of the controller's instantiation. As some of the answers above have pointed to, the route params are passed in asynchronously, so a controller with no bindings to that property won't execute. So, not sure exactly what you've distilled your snippet down from, but hope this helps!

This may happen (not in the OP's case) if you're using ui-router instead of ngRoute.
If that's the case, use $stateParams instead of $routeParams.
https://stackoverflow.com/a/26946824/995229

Of course it will be blank. RouteParams is loaded asynchronously so you need to wait for it to get the params. Put this in your controller:
$scope.$on('$routeChangeSuccess', function() {
console.log($routeParams);
});

It works for me http://plunker.co/edit/ziLG1cZg8D8cYoiDcWRg?p=preview
But you have some errors in your code:
Your don't seem to have a ngView in your code. The $routeProvider uses the ngView to know where it should insert the template's content. So you need it somewhere in your page.
You're specifying your CompanyCtrl in two places. You should specify it either in the $routeProvider, or in you template using ng-controller. I like specifying it in the template, but that's just personal preference.
Although not an error, you're specifying your CompanyCtrl in the global scope, instead of registering it on your Napp module using Napp.controller(name, fn).
Hope this helps!
You can always go on #angularjs irc channel on freenode: there's always active people ready to help

Could it be that your templateUrl points to an invalid template?
When you change the templateUrl to an unexisting file, you will notice that the $routeParams will no longer be populated (because AngularJS detects an error when resolving the template).
I have created a working plnkr with your code for your convenience that you can just copy and paste to get your application working:
http://plnkr.co/edit/Yabp4c9zmDGQsUOa2epZ?p=preview
As soon as you click the link in the example, you will see the router in action.
Hope that helps!

Related

Angular routing with ng-view is not working

I don't understand why I can't get this to work.
I'll share the relevant code, let me know if you need to see more stuff.
Index.html
<div class="col-md-3">Liberals</div>
app.js
var app = angular.module('myApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider.
when("/liberals", {
templateUrl: "partials/liberals.html"
, controller: "LiberalsController"
});
});
app.controller('LiberalsController', function ($scope, $http) {
var url = "workingURL"; /// changed function to a simple string message to test
$scope.message = "Hello Liberals";
});
(partial view) liberals.html
<h1>Hello</h1>
{{message}}
PS: I'm not working on a political hate website for or against liberals!
As of AngularJS 1.6, the default value of the hashPrefix has been changed to !.
There's two ways to get your routing to work with AngularJS 1.6+:
Add the hashprefix (!) to your href's:
Liberals
Change (remove) the hashPrefix value using $locationProvider:
$locationProvider.hashPrefix('');
I've created a working plunkr in which I used the second approach:
https://plnkr.co/edit/oTB6OMNNe8kF5Drl75Wn?p=preview
The commit regarding this breaking change can be found here

Why doesn't $location.path fire the $routeProvider function?

I'm trying to build my first AngularJS single page application. I copied part of the code below and modified it some. I have a menu bar which calls the Navigate method that I added to the mainController.
When I click on the menu button the expected alert message appears in Navigate, but the alert message in the $routeProvider function only fires when the application starts and it never fires again. I can't find a good explanation of this, but logic says the $routeProvider function should fire when a new $location.path is set in Navigate. Is that wrong? How is this supposed to wire up? Is my nested single page controller causing the menu command to fail?
Also, are there really supposed to be two semicolons at the end or should one of them come after the app.config section?
var app = angular.module('myApp', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider)
{
alert("$routeProvider " + $routeProvider.path);
$routeProvider
.when('/', {
templateUrl: 'App/Views/Home.html',
controller: 'homeController'
})
.when('/about', {
templateUrl: 'App/Views/About.html',
controller: 'aboutController'
})
.otherwise({
redirectTo: '/'
});
}])
app.controller('mainController', function ($scope)
{
$scope.Title = "Default Title";
$scope.Message = "Default Message";
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
$location.path(myPath);
};
});;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul class="MenuBar">
<li class="MenuButton FloatLeft" ng-click="Navigate('/home');">Home</li>
<li class="MenuButton FloatLeft" ng-click="Navigate('/about');">About</li>
<li class="MenuButton FloatLeft" ng-click="Navigate('/about');">Log In</li>
</ul>
You're trying to run an alert whenever the $routeProvider function runs but it doesn't quite work that way. The $routeProvider function just tells Angular "Whenever the location path changes, refer to this JSON object to know what to do next." Then your code providers some JSON attributes to Angular such as templateUrl and controller. Your alert function will only run once because the $routeProvider is just setup code to configure Angular's routes.
To run code after going to another "page", just add the code to the controller.
Code Example:
app.controller('homeController', function($scope, $http) {
alert("I'm running the homeController() function now");
});
Also, I noticed that you didn't inject $location into your controller. Without this, $location will just be an undefined object. Change your controller definition like this:
app.controller('mainController', function ($scope, $location)
{
$scope.Title = "Default Title";
$scope.Message = "Default Message";
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
$location.path(myPath);
};
});
Remember that any Angular object starting with the $ dollar sign ($timeout, $http, $routeProvider, etc) must be injected into your controller.
You have a few issues with the code you're showing. Not enough details to know for sure but here's what's wrong.
First:
A module's config block will only be executed once, at the start. You're not seeing the alert within your config beyond once because it's only ever called once during the bootstrap of your module.
Second:
You need to inject services that your controller depends on.
app.controller('mainController', function ($scope) { });
Note that you're missing the $location service here.
app.controller('mainController', function ($scope, $location) { });
Third:
We can't see some missing pieces to your code to help you out. You're not showing us how mainController is actually hooked up to anything. How myPath is being sent to the Navigation function on your controller, etc.
I found a nested controller that I wasn't using. When I took that out part of the menu worked. I say part because on some links instead of calling the Navigate function I was setting the window.location. That seems to fire the $routeProvider and the view changes like it should. When I change the Navigate function as shown below it works. I think setting $location.path() in the Navigate function should do the same thing, but it's not working for me.
$scope.Navigate = function (myPath)
{
alert("Navigate " + myPath);
//$location.path(myPath);
window.location = '#' + myPath;
};

Reading URL Query string

I have the following URL:
http://myUrl.com/#/chooseStyle?imgUpload=6_1405794123.jpg
I want to read the imgUpload value in the query string - I'm trying:
alert($location.search().imgUpload);
But nothing alerts, not even a blank alert - but console reads:
$location is not defined
I need this value to add into a controller to pull back data, and also to carry into the view itself as part of a ng-src
Is there anything I'm doing wrong? this is my app config:
capApp.config(function($locationProvider, $routeProvider) {
$locationProvider.html5Mode(false);
$routeProvider
// route for the home page
.when('/', {
templateUrl : '/views/home.html',
controller : 'mainController'
})
// route for the caption it page
.when('/capIt', {
templateUrl : '/views/capIt.html',
controller : 'mainController'
});
}):
This is the view:
<div class="container text-center">
<h1 class="whiteTextShadow text-center top70">Choose your photo</h1>
</div>
<script>
alert($location.search().imgUpload);
</script>
Main controller:
capApp.controller('mainController', function($scope) {
$scope.message = 'Whoop it works!';
});
My end goal is that I can find a solution to capturing and re-using data from the query string.
I will also mention, this is only my first week in Angular, loving it so far! A lot to learn...
<script>
alert($location.search().imgUpload);
</script>
You're making two mistakes here:
executing code while the page is loading, and the angular application is thus not started yet
assuming $location is a global variable. It's not. It's an angular service that must be injected into your controller (or any other angular component). This should cause an exception to be thrown and displayed in your console. Leave your console open always, and don't ignore exception being thrown.
You should not do this
<script>
alert($location.search().imgUpload);
</script>
// you need to inject the module $location
//(either in service, or controller or wherever you want to use it)
// if you want to use their APIs
capApp.controller('mainController', function($scope, $location) {
$scope.message = 'Whoop it works!';
//use API of $location
alert($location.search().imgUpload);
});

Is the angular ngRoute 'Controller' declaration necessary?

After reading both the api and the developer guide, I still don't understand the functionality provided by declaring 'controller' in a given route. Right now I just have my controllers declared as ng-controller directives in my views. Is ngRoute simply providing an alternative method?
To make my question explicit in code, see below:
--Index.html
...
<body ng-app="MyApp">
<div ng-view>
</div>
</body>
--View.html
<div id="myView" ng-controller="MyController">
...
</div>
--Route.js
var app = angular.module('MyApp', [ require('angular-route') ]);
app.controller('MyController', ['$scope', function ($scope) {
console.log('this gets executed as I would expect');
}])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', { templateUrl: '/Index.html' })
.when('/view', { templateUrl: '/View.html' });
// below line makes no difference as an alternative to above
//.when('/view', { templateUrl: '/View.html', controller: 'MyController' });
}]);
There are two ways to define controller for a view.
Either in the controller declaration in the ng-route
in the ng-controller for the view.
Either one is fine.
You should pick one option over the other since using both will actually give you duplicate controllers, i.e. both will be used. If you're using Routes, then you can specify a few additional properties such as resolve which has been mentioned in the comments and this will allow you to perform an action, or supply supplementary data etc.
Take a look at this article, Using Resolve In Angular, for more information.
Also, you should look into using Controller As, which sets you up for future proofing. John Papa has a few blogs and videos where he praises the use of Controller As and using the var vm = this; style syntax, take a look here.
Also, as a side note, you should use the .otherwise in your routes as this will capture any requests that are invalid and at least serve up a valid page from your site. You can see this in the routeProvider documentation.

Injection of angularFireCollection into angular.js config for usage in resolve

I've been experimenting a little with Angular.js lately. As part of this I created a very simple set of controllers with an ng-view and templates to trigger depending on the route requested. I'm using angularFireCollection just to grab an array from Firebase. This works fine in the thumbnailController which does not form part of the ng-view.
My problem is that in addition to the data flowing into the thumbnailController, I also need the two other controllers to be able to access the data. I initially simply set the data to either be part of $rootScope or to have the ng-view as a child of the div in which the thumbnailController is set.
However, the issue from that perspective is that each sub-controller presumably attempts to set the data in the template before it is actually available from Firebase.
The solution appears to be using resolve as per the answer to this question angularFire route resolution. However, using the below code (and also referencing angularFireCollection) I get an error message of angularFire being an unknown provider. My understanding is the code below should be sufficient, and I would also add that the usage of angularFireCollection in thumbnailController works fine as I say.
I also experimented with injecting angularFire/aFCollection directly into the controllers using .$inject however a similar issue arose in terms of it being considered an unknown provider.
If possible could someone advise on what the issue may be here?
var galleryModule = angular.module('galleryModule', ['firebase']);
galleryModule.config(['$routeProvider', 'angularFire', function($routeProvider, angularFire){
$routeProvider.
when('/', {
controller: initialController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
when('/view/:id', {
controller: mainimageController,
templateUrl: 'largeimagetemplate.html',
resolve: {images: angularFire('https://mbg.firebaseio.com/images')}
}).
otherwise({
redirectTo: '/'
});
}]);
galleryModule.controller('thumbnailController', ['$scope', 'angularFireCollection', function($scope, angularFireCollection){
var url = 'https://mbg.firebaseio.com/images';
$scope.images = angularFireCollection(url);
}]);
function initialController($scope,images){
$scope.largeurl = images[0].largeurl;
}
function mainimageController($scope, images, $routeParams){
$scope.largeurl = images[$routeParams.id].largeurl;
}
I got the chance to dig into this a little bit - it seems like regular services cannot be used in .config sections. I'd instantiate angularFire in the controller instead of using resolve, for example:
galleryModule
.value("url", "https://mbg.firebaseio.com/images")
.controller('thumbnailController', ['$scope', 'angularFireCollection', 'url',
function($scope, angularFireCollection, url) {
$scope.images = angularFireCollection(url);
}])
.controller('initialController', ['$scope', 'angularFire', 'url',
function($scope, angularFire, url) {
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[0].largeurl;
});
}])
.controller('mainimageController', ['$scope', 'angularFire', '$routeParams', 'url',
function($scope, angularFire, $routeParams, url){
angularFire(url, $scope, 'images').then(function() {
$scope.largeurl = $scope.images[$routeParams.id].largeurl;
});
}]);
This is not ineffecient, since the data is only loaded once from the URL by Firebase, and all subsequent promises will be resolved almost immediately with data already at hand.
I would like to see angularFire work with resolve in the $routeProvider, however. You can use this method as a workaround until we figure out a more elegant solution.

Resources