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.
Related
When using ui-router in Angular JS, what dependencies can be injected into onEnter callbacks? Specifically, I want to use the $http service and a constant defined in the parent module. The code I am working with defines ui-router states in module config; I know I cannot use services in config code, but maybe it's ok to use them in callbacks defined by config code? At any rate, the following code seems to work; I am just worried it may not be reliable. I guess
the real question is, when are dependencies injected? Does this happen at the time that a function is defined, or at the time that a function is called?
angular.module('sim', ['ui-router']).
constant('ENV', {
BASE_URL: '/simulation/secure'
}).
config(config);
function config($stateProvider) {
$stateProvider
.state('root.training', {
url: '/training',
controller: 'trainingCtrl',
onEnter: function($http,ENV)
{
$http.get(ENV.BASE_URL + '/setIsRunning');
}
});
};
The dependencies are injected when the function is called. Looking at the source code of ui-router, the onEnter-callback is called during a state transition, when the transition is considering entering. The call to the onEnter-callback is done using Angulars $injector.invoke() function, which resolves any dependencies in the $injector and invokes the method, as per the angular documentation. So pretty much any dependency should be valid to use in onEnter.
Suppose I have a function in my controller and a variable. And there's another controller with another function that takes a variable as parameter.
I need to redirect to that controller from my controller, call that function, and pass variable value from my controller.
How can I do this in a single page application?
Its a lot like when we redirect from one page to another in MVC and pass a value through URL. I'm trying to pass a variable to another controller that has its own page.
You can do it two ways.
One is through angular services and other is via ui-routing resolve functionality.
Services are more preferable according to best practices standards.
You should use $routeParams to get the behavior similar to MVC. Just define a route like this:
{
url: '/page/:pageNo',
config: {
templateUrl: "page.html",
controller: "pageController"
}
}
From the controller you want to redirect from, use $location.path
$location.path('/page/' + $scope.pageNo);
Finally, in the controller where you redirect to, you will access this param using $routeParams
$routeParams.pageNo
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.
I wonder what's the best way to configure a route which only purpose is to make use of a service call and then redirect.
I'm currently using this hack:
$routeProvider.when('/talks', {
template: '<div></div>',
controller: ['dateService', '$location', function(dateService, $location){
var nextTalk = dateService.getNextTalkDate();
$location.path('talks/' + nextTalk.format('MM') + '/' + nextTalk.format('YYYY'));
}]
});
Currently I set the controller configuration to an inline controller implementation which has dependencies on the services and then does it's thing and redirects.
However, it feels a bit weird, since I have to set template to some dummy value because otherwise the controller would not be invoked at all.
It feels as if I'm stressing the controller property for something it wasn't intended for.
I guess there should be a way to run some view unrelated code that has access to services on a route. I could right my own $routeProvider I guess but that seems to be a bit heavy for something I would consider should be built in.
Looks like '/talks' is a kinda abstract since its just used to redirect to other routes.. So how about setting up a route like this:
''/talks/:month/:year'
Where :month and :year is optional. If no month or year is given, your service returns a default talk. Which is probably the next talk. If params are given you just fetch the requested data.
So there's no redirect required. Now you specifiy the controller and the needed view and expose your data on the scope. Optionally would it be better to wrap your service call in a promise and resolve it at routeProviders resolve property.
This makes sure that the view only change if everything's resolved fine.
Hope that helps!
There's no way to inject services into anywhere into a route. Whether it be redirectTo or template, any code in there is handled on the module level. This means that the module is loaded first and then when the application has boostrapped itself then the services and injection-level code is executed. So the controller is your best bet (since that does support injection).
Controller is used in a lot of areas in AngularJS and it should work fine for what you're trying to do. You can either handle the redirection like you do in there or you can setup three different routes that point to the same controller (where you build the page).
var handler = { controller : 'Ctrl' };
$routeProvider.when('/talks', handler).
when('/talks/:month, handler).
when('/talks/:month/:year', handler);
And if you do end up using redirection, then just use $location.path(url).replace(). This will make the history stack jump back one level and therefore that the redirection triggering URL won't be in your history.
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.