Using Angular I have a dozen or so routes setup similar to the following example code.
Is there a way to override which template and controller is loaded based on some other criteria while keeping the URL in tact? My goal is to display a login page when... lets say $scope.isLoggedIn = false. I don't want to change the URL to /login.
SomeApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/place', {
templateUrl: 'routes/place.html',
controller: 'PlaceCtrl'
})
.when('/test', {
templateUrl: 'routes/test.html',
controller: 'TestCtrl'
});
}]);
ngRoute is a very simple library that can basically only maps urls to controller/views. If you want more flexibility, try ui-router which has the ability to route based on state.
This isn't really doable with ngRoute, but with ui-router you can dynamically provide different templates based on just about anything you want.
$stateProvider.state('root',
url: '/'
controller: 'HomePageController'
templateProvider: [
'$rootScope'
'$templateCache'
'$http'
($rootScope, $templateCache, $http) ->
templateId = if $rootScope.isLoggedIn then "home-page-logged-in" else "home-page-not-logged-in"
templateId = "/templates/#{templateId}.html"
return $http.get(templateId, cache: $templateCache)
]
)
The catch is, as far as I know, you can't change the controller, only the template. Which kinda stinks.
Related
For some reason, I can't seem to route to the add screen. What am I doing wrong? Here's my app.js
var moviesApp = angular.module('moviesApp', ['ngRoute']);
moviesApp.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/home.html',
controller: 'MoviesController'
})
.when('/add', {
templateUrl: 'partials/add.html',
controller: 'MoviesController'
})
.when('/edit', {
templateUrl: 'partials/edit.html',
controller: 'MoviesController'
});
});
Here's the anchor tag:
Add Movie
Which is contained within my home.html template which is a part of index.html.
The app doesn't crash...it just doesn't do anything.
Any thoughts on what I'm doing wrong?
It may be because of the change in the default hash-prefix in angularjs version 1.6. What you have written works in the given context: Proof
You can confirm this is the case by changing:
Add Movie
to:
Add Movie
If it works look at for possible solutions at:
AngularJS: ngRoute Not Working
If you want to make i behave as you expect (version 1.5) you could choose soultion 3 from the link:
3. Go back to old behaviour from 1.5 - set hash prefix manually
app.config(['$locationProvider', function($locationProvider) {
$locationProvider.hashPrefix('');
}]);
set up a route start event to help debug the problem
.run(function ($rootScope) {
$rootScope.$on('$routeChangeStart', function (event, next, current) {
console.log(event);
console.log(current);
console.log(next);
console.log('$routeChangeStart: ' + next.originalPath)
});
});
just add this to the end of your route config
Just as a side note I would use a state provider over a route provider. State providers let you define a hierarchy. It's a little harder to work with but much more flexible.
The problem I'm having here is not being able to find the right question to ask.
I'd like to use a single partial and populate it with different data based on a url. The url would look something like this
localhost:8080/#/users/USER_ID
Where users directs to a user profile partial, and corresponding controller, and USER_ID would be sent in to an HTTP request to retrieve user data that would then populate the user profile partial.
Any direction in solving this is greatly appreciated.
If you are using ui-router which I highly recommend:
$stateProvider
.state('users', {
url:'/users/:userId',
templateUrl: 'user.html',
controller:'UserCtrl'
})
You can then access the userId in your controller:
App.controller('UserCtrl', ['$scope', '$stateParams', '$state', 'User', function($scope, $stateParams, $state, User) {
'use strict';
/* controller code */
var req = User.$find($stateParams.userId);
}]);
I am also using angular-rest-mod to make HTTP calls to an api when I do User.$find(id)
I found a solution that was a lot more straight forward than I had anticipated
app.js
$routeProvider.
when('/user/:id', {
templateUrl: 'user.html',
controller: 'userController'
});
Then in the implementation of userController, $routeParams can be used to retrieve the value of id from the url.
Okay so I would probably go like this. First I would recommend Ui-Router instead of ngRoute this allows you to create your states for example
$stateProvider
// setup an abstract state for the tabs directive
.state('A', {
params: [A,B,C,D,E],
url: "/A",
templateUrl: "templates/YourView.html",
controller: "YourController"
})
.state('B', {
params: [F,G,H,I,J],
url: "/B",
templateUrl: "templates/YourView.html",
controller: "YourController"
})
Basically this says when your Url is "/A" the "YourController" is used and the YourView.html is used so If I understood correct you have 1 view where you want to show different data depending on the Url.By Injecting 'ui.router'into your module and $state into your Controller you can access $state.current.params
Example Controller
.controller('ExampleController', ['$rootScope', '$scope', '$state', function ($rootScope, $scope, $state){
//Here you get your params
//This will return you either [A,B,C,D,E] or [F,G,H,I,J] depending if Url is /A or /B
$scope.showList = $state.current.params;
//Another Possibility with this is to listen for a StateChange
$scope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
//Here you can access all Params from the state you just left to the state you are going
});
}]);
Now you can just show this in the YourView.html like this
<div ng-repeat="item in showList">
<p>{{item}}</p>
</div>
So If your at /A the list shows A,B,C,D,E and if you are on /B it shows F,G,H,I,J
I hope this was helpful
I am using the Angular $routeProvider service to wire-up my single-page HTML5 applciation. I am using the following routing configuration:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/show-order/:orderId', {
templateUrl: 'templates/order.html',
controller: 'ShowOrdersController'
});
}]);
Within the ShowOrdersController I need access to the RESTful URL parameter described above as :orderId. It is suggested that to best achieve this, I should use the $routeParams service in my controller:
app.controller('ShowOrderController', function($scope, $routeParams) {
$scope.order_id = $routeParams.orderId;
});
I have serious concerns about this. My routing logic has now bled through to my controller! If I want to drastically change the routing scheme, I would have to go through all my controller code and correct all the references to $routeParams.
Furthermore, if I want to re-use the ShowOrderController for multiple routes, it's going to enforce all of the routes to use the same token variable :orderId.
This just seems like poor coding to me. It would make more sense to provide some linking mechanism, so the router can specify well-known parameters to the controller.
This would be just like how a modal's resolve method works:
$modal.open({
controller: 'ShowOrderController',
resolve: {
orderId: function () {
return $routeParams.orderId;
}
}
});
app.controller("ShowOrderController", ["orderId", function (orderId, $scope) {
$scope.orderId = orderId;
}]);
Is there any way to achieve this or something similar with the out-of-the-box AngularJS routing services?
As per AngularJS - How to pass up to date $routeParams to resolve? it is possible to reference the current route's parameters in the resolve method of the $routeProvider using $route.current.params:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/show-order/:orderId', {
templateUrl: 'templates/order.html',
controller: 'ShowOrdersController',
resolve: {
orderId: function( $route ) {
return $route.current.params.orderId;
}
}
});
}]);
This will then honour the suggestion above, that the controller can declaratively specify its parameters:
app.controller("ShowOrderController", ["orderId", function (orderId, $scope) {
$scope.orderId = orderId;
}]);
In conjunction, this effectively decouples the controller from the route's parameters.
I have an Angular JS application with a defaultController which controls the header of the app. Then I have some other controllers one for each view. The views are loaded in the <main>. I load the views using the $routeProvider with this code:
myapp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'templates/login.html',
controller: 'loginController'
}).
when('/dashboard', {
templateUrl: 'templates/dashboard.html',
controller: 'dashboardController'
}).
...
I am trying to display a LOGOUT button inside the header when the loaded view is the dashboard and hide it if the loaded view is the login view. In order to do that I have on the defaultController the $location object and I properly add and remove classes from the LOGOUT button with ng-class.
There is only one problem: $location gives me the correct path the first time I load the page, but after I change the view (changed by the $routeProvider) that variable is not updated anymore, so when I am actually on /#/dashboard , the $location.url is still on /login. Here the controller code:
controllers.controller('defaultController', ['$scope', 'ipCookie', '$location', function($scope, ipCookie, $location) {
$scope.url = $location.url();
...
I also tried with $window.location.hash with the same result.
Any idea?
EDIT: after the accepted answer this is what I ve added on the defaultController in order to make it work
$scope.$on("$locationChangeSuccess", function() {
$scope.url = $location.url();
});
The location is probably updated in the service after your default controller is loaded.
You can either inject the $location service into the scope and make decisions in your template based on it (then it will automatically be watched and re-evaluated) or you could listen for the $locationChangeSuccess event.
When injecting, you can simply $scope.location = $location and then use something like <a ng-hide="location.path() != '/something'">.
$location broadcasts the $locationChangeSuccess on the root scope, so you should be able to listen for it on whichever scope you have available: $scope.$on( "$locationChangeSuccess", function() { /* do something */ } );
I'm working on a file editing application in AngularJS. My urls look like this:
#/fileName.md
or
#/folder/fileName.md
or
#/folder/nested-folder/another-folder/itgoesonforever/filename.MD
I don't want to have to do a route for every single depth and it could be ~15 routes deep. Are there any ways to have conditional routes? Crudely:
/:fileorfolder?/:fileorfolder?/:fileorfolder?/:fileorfolder?
I think the best you can do with Angular is *, which is new as of v1.1.5 of $routeProvider:
path can contain named groups starting with a star (*name). All characters are eagerly stored in $routeParams under the given name when the route matches.
For example, routes like /color/:color/largecode/*largecode/edit will match /color/brown/largecode/code/with/slashes/edit and extract:
- color: brown
- largecode: code/with/slashes
You'd have to parse the largecode param yourself though.
I think I got it! The trick is to set the template to a simple , then modify the scope to include the dynamic path to your template.
So now I can place a file at /foo/bar/baz.html and see the template rendered by going to server.com/foo/bar/baz.
// Routes
app.config( function($routeProvider) {
$routeProvider
// Home
.when( '/', {
templateUrl: 'home.html',
controller: 'HomeController'
})
// Catch All
.when( '/:templatePath*', {
template: '<ng-include src="templatePath"></ng-include>',
controller: 'CatchAllCtrl'
})
});
// Catch All Controller
app.controller("CatchAllCtrl", function($scope, $routeParams) {
$scope.templatePath = $routeParams.templatePath + '.html';
});
You could look at using the routeProvider#otherwise functionality
$routeProvider
.otherwise({controller: 'FileEditor',...});
http://docs.angularjs.org/api/ng.$routeProvider