$routeParams not available during controller initialization - angularjs

I'm trying to figure out AngularJS and routing. Can someone take a look at this http://jsfiddle.net/spoon16/p9BBr/
Help me understand why $routeParams.i is undefined during initialization. What is the appropriate way to use $routeParams in my controllers?

Basically $routeParams isn't available until the route service has changed the route, meaning you should only inject the service in controllers associated with a specific route (the controller property for the route).
If you in some other controller needs to know current route etc. you should listen to the various events the route service broadcasts, e.g.
$scope.$on('$routeChangeSuccess', function (ev, current, previous) {
// ...
});
Updated fiddle.

Related

Capturing the route change in AngularJS when no route matches

In AngularJS, is there a way to intercept a route change that is not defined in the routeProvider so the route can be looked up in the database and, if a valid match in the database, the new route can be added to the routeProvider?
I've read it is possible to add, dynamically, a route, but I need to do it when the current route has no match.
I would have used the otherwise method of $routeProvider to load a predefined page (controller) to handle undefined routes.
otherwise({
templateUrl: 'addRoute.html',
});
And then, into this controller, get the current route requested using $location ($location.url()).
Add this route dynamically if needed :
$route.routes['/new'] = {templateUrl: 'new.html'};
Finally, redirect to this route using :
$location.path('/new');
Obviously, for this to work you will need to inject $route and $location as dependency to your controller.
Assuming you can do it in controller, you can capture this event as following:
$rootScope.$on("$routeChangeSuccess", function (event, next, current) {
if(!angular.isDefined($route.current.$$route))
addDynamicRoute('using techniques mentioned above');
else
handleOtherStuff();
});

How to get the `$location` before `$routeProvider` redirect?

I'm doing a redirect in the angularjs config and I can see the initial location there:
$routeProvider.otherwise({
redirectTo: function(dummy, path, search) {
return "/default-page";
}
});
The problem is how to pass this information anywhere else.
I can't inject a service in the config.
I can't inject the $rootScope either (so I can't broadcast it).
I can inject the $rootScopeProvider, but have to use its $get.
I can listen to $routeChangeSuccess but I can't see there the original location.
I can listen to $routeChangeStart, but it's no better.
What do I want it for: Unlock a feature by using a "magic" URL like
.../#/cheat/a/lot?answer=43
It's just a debugging hack, nothing security relevant.
I guess I should do it differently (a normal page calling $location?), but now I'm curious...
Me stupid.
After having spend quite some time trying to figure it out and then writing the question....
Inject $rootScope and $location into the service and use it in
$rootScope.$on("$routeChangeStart", function() {...})

Angular: Inject dynamically into my controllers

I need to inject an extra object to my controllers dynamically so I thought it'd be best to do it in the run function like so:
angular.module("app").run([
"$rootScope", "$inject", "repository.user", function ($rootScope, userRepository) {
$rootScope.$on("$routeChangeStart", function (event, next, current) {
var controller = next.$$route.controller;
userRepository.getSession(function(data) {
// What do do now?
});
});
}
]);
I'd like to inject that returned data into my controllers but I'm not sure how to do it?
Take a look at the $routeProvider documentation, specifically the resolve configuration option for a route. Have you thought about using this to dynamically resolve your dependency?
resolve - {Object.=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired. The map object is:
key – {string}: a name of a dependency to be injected into the controller.
factory - {string|function}: If string then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before its value is injected into the controller. Be aware that ngRoute.$routeParams will still refer to the previous route within these resolve functions. Use $route.current.params to access the new route parameters, instead.
If I understand correctly, you are trying to collect user login state for every route change. Why not just save the data in $rootScope as something like $rootScope.currentUser = data.
This way you can access $rootScope.currentUser from any controller.

Angular ui router : calling method on controller from onEnter

My ui router config is like this:
$stateProvider
.state("list",{url:"/list",templateUrl:"list.html",controller:"ctrl as vm"})
.state("list.select",
url:'/select',
templateUrl:'select.html',
onEnter:function( ) { ... }
});
The list.select state uses the same controller as the list state. How can I call a method on the controller from the onEnter function? Note that I'm using the "ctrl as vm" syntax! Can I also access $stateParams here?
You can certainly access $stateParams in onEnter, as well as any other service. However, there's no way to inject the current or parent (or any other) controller instance.
So, while you can't invoke a method on the controller this way, you can use onEnter or resolve to preprocess something and perhaps use a flag for list.select to check and call that method.
It also may make more sense to use a service to coordinate this functionality, but I don't know the purposes of your approach so I'd need to know more.

Common Controller for ng-view

Is there a way to call a common controller everytime ng-view is changed? i.e i want a common controller to be called everytime a new $route is loaded.
If you have specified custom controllers for your different routes, then there's no way that I know of that you can also specify a common controller that always gets invoked, unless you use some kind of inheritance and always call a method in the base controller.
An alternative approach is to subscribe to the events the route service broadcasts.
Example:
function MyController($rootScope, [...]) {
$rootScope.$on('$routeChangeSuccess', function (current, previous) {
// ...
});
}
You have a list of available events and their parameters here.
I believe you also can add properties, methods etc. to $rootScope which you can use in bindings in your views thanks to how Angular's binding mechanism works. If it doesn't find it on the current scope, it checks its parent etc. up to the root scope.

Resources