Can I set a default value of a parameter of a route in AngularJS? Is there a way to have /products/123 and /products/ handled by the same route ?
I'm looking to refactor my existing code, which looks like:
myModule.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/products/', {templateUrl: 'products.html', controller: ProductsCtrl}).
when('/products/:productId', {templateUrl: 'products.html', controller: ProductsCtrl})
}]);
function ProductsCtrl($scope, $routeParams) {
$scope.productId = typeof($routeParams.productId) == "undefined" ? 123 : $routeParams.productId;
}
It works, but it's not very elegant. Is there a better way ?
I recognize that this question is old, but still: Why don't you just redirect the "empty" URL to one containing the default productId?
myModule.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/products/', {redirectTo: '/products/123'}).
when('/products/:productId', {templateUrl: 'products.html', controller: ProductsCtrl})
}]);
AngularJS does not allow default values for route parameters.
But routes (in AngularJS) should not have default parameters.
Resources could have default parameters.
In AngularJS if you want a route with an optional parameter, these are actually two different routes.
Why?
Routes should be simple
Routes does not allow regular expressions matching for parameters
Routes are not something which exposes an API to work in your application (unlike Resources do). Routes are just configuration which connects a URL with a template and a controller. Thus having more routes is better:
It is clear which route maps to which url.
It is more verbose, but simpler to read. Having more complex routes would create a steeper learning curve where AngularJS does not need one.
Unlike server-side frameworks which have routes
AngularJS routes do not have names.
You do not build URLs from the defined routes.
You do not have logic (a.k.a functions) in the routes definitions.
Simpler routes = more lines to define them = less headaches working with them.
NOTE: Please keep in mind the question and this answer are for an old version of AngularJS (1.0 I think) pre-dating the new routes/resources implementation.
I had a similar requirement. What i did was to create a function to resolve. Something like below
myModule.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/products/', resolveProduct()).
when('/products/:productId', resolveProduct())
}]);
function ProductsCtrl($scope, $routeParams) {
$scope.productId = $routeParams.productId;
}
function resolveProduct() {
var routeConfig = {
templateUrl: 'products.html',
controller: ProductsCtrl,
resolve: {
productId: ['$route', function($route){
var params = $route.current.params;
params.productId = params.productId || 123;
}]
}
}
return routeConfig;
}
With url: "/view/:id/:status?", You can indicate an optional parameter.
Just thought someone may need it.
Not sure if this question is specific to $routeProvider but in $stateProvider, you can achieve this by
myApp.config(function($stateProvider) {
$stateProvider
.state('products', {
url: '/:productId',
templateUrl: "/dashboard/products.html",
controller: 'ProductController',
params: {
productId: {
value: "defaultValue",
squash: true // or enable this instead to squash `productId` when empty
}
}
});
});
Related
I have a hard time understanding this. I'm attempting to put controllers in separate files so that they only deal with 1 thing, ideally, a partial view
My folder structure is like this...
My app.js file is like this.
angular.module('mikevarela', ['ui.router', 'mikevarela.controller.home', 'mikevarela.controller.about', 'mikevarela.controller.audio'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: '../partials/home.partial.html',
controller: 'HomeController'
})
.state('about', {
url: '/about',
templateUrl: '../partials/about.partial.html',
controller: 'AboutController'
})
.state('audio', {
url: '/audio',
templateUrl: '../partials/audio.partial.html',
controller: 'AudioController'
});
});
and my controllers each have a module like this...
angular.module('mikevarela.controller.home', [])
.controller('HomeController', ['$scope', function($scope) {
$scope.title = 'Mike Varela Home Page';
}]);
My issues comes with the intial app declaration. I don't want to have to inject all the controllers in the main array app definition, that would be cumbersome and long winded. Isn't there a way to define the controller at the controller file. Kind of like this
angular.module('mikevarela', []).controller('HomeController', ['$scope', function($scope) {
// stuff here
}]);
Use angular.module('mikevarela').controller..... in subsequent files.
angular.module('mikevarela',[]).controller.....
is equivalent to redefining your app. The second param is requires array.
Quoting official angular.module docs
requires
(optional)
!Array.=
If specified then new module is being created. If unspecified then the module is being retrieved for further configuration.
About your Controllers...
I think you're loading the controllers incorrectly.
You don't need to declare controllers as a dependency. Rather stating module.controller('yourController)` makes that controller available throughout the module.
If your controllers are in separate files, all you need to do to make it available is load it in with a script tag. e.g.
<script src="app.js"></script>
<script src="controller1.js"></script>
<script src="controller2.js"></script>
About your Application Structure...
This is not related to your question, but just coming from someone who's developed using Angular, I'd recommend not grouping your application by controllers/ by rather by feature. See: https://scotch.io/tutorials/angularjs-best-practices-directory-structure
I'm writing a simple product information management app using angular js. To keep my app as modular as possible i've split it into multiple modules with one module "pim" as startpoint. For each module I want to have a different route, so that it is easy to plug in a new module or remove it without having to maintain a huge route in the pim module config.
Currently I have two routes (the first route):
(function(){
angular
.module("pim")
.config(router)
function router($routeProvider){
$routeProvider
.when("/",{
templateUrl: "view/info.html",
controller: "pimController"
})
.when("/info",{
templateUrl: "view/info.html",
controller: "pimController"
})
.when("/alcohol",{
templateUrl: "view/alcohol.list.html",
controller: "alcoholController"
});
}
})();
The second route
(function(){
angular
.module("alcohol")
.config(router)
function router($routeProvider){
$routeProvider
.when("/alcohol/list",{
templateUrl: "view/alcohol.list.html",
controller: "alcoholController"
})
.when("/alcohol/info",{
templateUrl: "view/alcohol.info.html",
controller: "alcoholController"
});
}
})();
As you can see /alcohol has a templateUrl and a controller, the same as /alcohol/list, but i want to know if there is a simple (standard) way to change to another URL for example /alcohol/list, so that I do not have to repeat the templateUrl and controller and keep this information in the alcohol module, where it belongs.
For example
.when("/alcohol",{
routeTo: "/alcohol/list"
})
Thank you for your help
SOLVED
The option to redirect exists, did not look in the $routeProvider documentation well enough:
.when("/alcohol",{
redirectTo:"/alcohol/list"
});
The code above works
You can use $routeProvider's redirectTo route map.
.when("/alcohol", {
redirectTo: "/alcohol/list"
});
Read more: https://docs.angularjs.org/api/ngRoute/provider/$routeProvider
I create single page app by AngularJS and I found my problem. I have function refresh data every 2 minutes by jQuery in route A. When I change to other route, that function in controller is still working. This is my code.
App.js
var newsapp = angular.module('newsAppMD', ['ngRoute']);
newsapp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/news', {
templateUrl: 'templates/news.html',
controller: 'imageNewsCtrl'
}).
when('/news/:nameCat', {
templateUrl: 'templates/news-thumbnail.html',
controller: 'newsPageCtrl'
}).
otherwise({
redirectTo: '/news'
});
}]);
newsapp.controller('imageNewsCtrl', function($scope, $http, $interval, $timeout ) {
$('#bottom-bar').find('#epg').hide();
$scope.updateTimeEPG = 120000;
$scope.fetchFeed = function() {
$http.get("http://wi.th/thaipbs_tv_backend/epg_forJS.php").success(function(response) {
$scope.items = response.Schedule;
console.log($scope.items);
$timeout(function() { $scope.fetchFeed(); }, $scope.updateTimeEPG);
}).then(function() {
$('#bottom-bar').find('.loading').hide();
$('#bottom-bar').find('#epg').show();
});
};
$scope.fetchFeed();
});
newsapp.controller('newsPageCtrl', function($scope, $http, $location) {
// blah blah blah
}]);
I choose /news imageNewsCtrl work. And when I switch to other route, function in imageNewsCtrl still work (I see function print console.log when I changed route). I want to stop function in controller when change route. Thanks for your suggestion everyone. :)
I am not too entirely sure, but try using $stateProvider instead of $routeProvider. If you do, then you need to npm install angular-ui-router (it is a powerful third party module) and replace ngroute. I only user $routeProvider for the .otherwise function. You can also do a lot more cool stuff like onEnter and onExit with $stateProvider. Another thing is I would recommend you to use only Angular instead of jQuery. I do not really see a point of you using both. Use Angular's two-way data binding! Also, if you really want to get into Angular, then I recommend John Papa's style guide. This guys knows what he is talking about for making a great Angular app. I hope this info helps!
I'm used to defining angular controllers with the inline array notation, e.g.:
angular
.controller('SomeCtrl', [ '$scope', function($scope) {
...
}])
I also prefer the fluent API for angular modules, i.e. there is only a single angular.module call at the top of my file defining the controllers, and everything else is chained to this call.
I would now like to use ui-router's resolve feature, and keep the controller dependency with the controller, not in the router (see the recommendations on routing resolves).
Is there a way to continue using my preferred approaches (inline array notation, fluent API) together with the recommendations for ui-router's resolve? My current understanding is that angular.controller defines the constructor for a controller, so in order to have an additional resolve() method on the controller I would have to pass in an object that already has this method plus a constructor.
Update: adding a code sample.
Route:
function config ($routeProvider) {
$routeProvider
.when('/myroute', {
templateUrl: 'views/some.html',
controller: 'SomeCtrl'
resolve: SomeCtrl.resolve
});
}
Controller:
angular
.controller('SomeCtrl', [ '$scope', 'SomeService', function($scope, SomeService) {
var data = SomeService.data;
...
}])
Where SomeService.data() is the method call that returns the promise I need resolved. How do I define the resolve using my preferred approaches?
SomeCtrl.resolve = {
data: function(SomeService) {
return SomeService.data();
}
};
You can keep using the inline annotations. You will just need an annotation for the name of the model that you are resolving.
So if your resolve has a method named getPromise, your inline controller DI annotation should contain the string 'getPromise'.
UPDATE
So with your code examples you should make the following changes.
Add 'resolve annotations' to your resolve object:
SomeCtrl.resolve = {
'SomeService': SomeService,
someData: ['SomeService', function(SomeService) {
return SomeService.data();
}]
};
Add an annotation to the resolve method. I have changed it from 'data' in your example to 'someData' here:
angular
.controller('SomeCtrl', [ '$scope', 'someData', function($scope, someData) {
var data = someData;
...
}])
Another UPDATE
Ok. I think I understand the question now.
You do not need to define the uiRouter resolve with SomeCtrl.resolve.
You can define the resolve inline in the module config section:
function config ($routeProvider) {
$routeProvider
.when('/myroute', {
templateUrl: 'views/some.html',
controller: 'SomeCtrl'
resolve: {
'SomeService': SomeService,
someData: ['SomeService', function(SomeService) {
return SomeService.data();
}]
}
});
}
Or if you want to get fancy, you can create a resolve object with keys for each of your state and then do some thing like:
...
resolve: myResolveObj.someState
...
I have a reset link, which is meant to reset my angular js app...
<a ng-click="resetApp()">reset</a>
I am handling the button press in the main controller...
$scope.resetApp = function(){
if(confirm("You will lose data...")){
$scope.user.reset();
// not sure how to do this in more angular js way
window.location = "/#";
}
}
I am not sure if setting the window.location as I have done is the right way to do things. It works for me, but does not seem like the correct way, and I have not been able to find out ow to do it online.
I have been using the so-called AngularJS way like this, at least the routing is handled by AngularJS rather than browser directly.
function Ctrl($scope, $location) {
$scope.resetApp = function(){
...
$location.url('/');
}
}
The path is what is defined in the Route Provider like this:
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'index.html',
controller: 'Ctrl'
}).
...