How to reuse controllers in AngularJs when success locations are different and $location.path('..') is not supported?
-
21-12-2019 - |
Question
Right now the $location service is getting in the way. Suppose one wants to use the same controller for multiple routes, however the expectation is that upon a successful 'save' the destination routes would be different.
.when('/sponsors/:sponsorId/games/add', {templateUrl: 'partials/games/create',controller: 'GameCreateCtrl', access: 'sponsor'})
// an admin can see all the games at
.when('/admin/games/add', {templateUrl: 'partials/games/create',controller: 'GameCreateCtrl', access: 'admin'})
A game is is displayed on success of either action. The route is just the parent path. e.g. /admin/games or /sponsors/:sponsorId/games.
The $location service does not seem to support the relative path $location.path('..'). Should it? What is the best way to reuse the GameCreateCtrl in this situation?
$scope.save = function () {
GameService.save($scope.game).$promise.then(function(res){
console.log(res);
growl.addSuccessMessage("Successfully saved game: " + $scope.game.name);
console.log("saving game by id:" + $scope.game._id);
var path = $location.path();
$location.path(path.replace('/add', '')); // this seems like a hack
});
}
Solution
You can do it with resolve
:
.when('/sponsors/:sponsorId/games/add', {
templateUrl: 'partials/games/create',
controller: 'GameCreateCtrl',
resolve: {
returnUrl: function($routeParams){
return '/sponsors/' + $routeParams.sponsorId + '/games';
}
}
})
.when('/admin/games/add', {
templateUrl: 'partials/games/create',
controller: 'GameCreateCtrl',
resolve: {
returnUrl: function(){
return '/admin/games';
}
}
})
In controller:
app.controller('myCtrl', function($scope, returnUrl){
$scope.save = function () {
GameService.save($scope.game).$promise.then(function(res){
// ...
$location.path(returnUrl); // this seems like a hack
});
};
});
You are passing different returnUrl
parameter to controller depending on route.
OTHER TIPS
I would like to thank the poster karaxuna with their solution. Its the answer I am accepting. However, it is often helpful to have other options at ones disposal.
Another way to solve this would be to create a global function.
function getParentPath($location) {
if ($location.path() != '/') /* can't move up from root */ {
var pathArray = $location.path().split('/');
var parentPath = "";
for (var i = 1; i < pathArray.length - 1; i++) {
parentPath += "/";
parentPath += pathArray[i];
}
return parentPath;
}
}
This works very where when edits/adds follow a rest style with regards to route locations. In these cases the parentPath would always go back to the plural listing of all records.
and perhaps add a method to root scope
$rootScope.goParentPath = function ($location) {
$location.path(getParentPath($location));
}
function inside controllers could call the getParentPath function. e.g.
$scope.cancel = function() {
$scope.goParentPath($location)
}
I am actually leaning considering an approach that combines the first answer with a getParentPath is some situations.
For a little bit of brevity, the routes would make use of the resolve callout, but use the parentPath function in many cases. ex:
.when('/admin/games/:id', {templateUrl: 'partials/games/edit', controller: 'EditGameCtrl', access: 'admin',resolve:{returnUrl: getParentPath}})
.when('/admin/games/add', {templateUrl: 'partials/games/create', controller: 'EditGameCtrl', access: 'admin', resolve:{returnUrl: getParentPath}})