Saturday, 19 November 2016

Can you change a path without reloading the controller in AngularJS?



It's been asked before, and from the answers it doesn't look good. I'd like to ask with this sample code in consideration...




My app loads the current item in the service that provides it. There are several controllers that manipulate the item data without the item being reloaded.



My controllers will reload the item if it's not set yet, otherwise, it will use the currently loaded item from the service, between controllers.



Problem: I would like to use different paths for each controller without reloading Item.html.



1) Is that possible?



2) If that is not possible, is there a better approach to having a path per controller vs what I came up with here?




app.js



var app = angular.module('myModule', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}).
when('/items/:itemId/foo', {templateUrl: 'partials/item.html', controller: ItemFooCtrl}).
when('/items/:itemId/bar', {templateUrl: 'partials/item.html', controller: ItemBarCtrl}).
otherwise({redirectTo: '/items'});
}]);



Item.html




Foo
Bar





controller.js



// Helper function to load $scope.item if refresh or directly linked
function itemCtrlInit($scope, $routeParams, MyService) {
$scope.item = MyService.currentItem;
if (!$scope.item) {
MyService.currentItem = MyService.get({itemId: $routeParams.itemId});
$scope.item = MyService.currentItem;
}

}
function itemFooCtrl($scope, $routeParams, MyService) {
$scope.view = {name: 'foo', template: 'partials/itemFoo.html'};
itemCtrlInit($scope, $routeParams, MyService);
}
function itemBarCtrl($scope, $routeParams, MyService) {
$scope.view = {name: 'bar', template: 'partials/itemBar.html'};
itemCtrlInit($scope, $routeParams, MyService);
}



Resolution.



Status: Using search query as recommended in the accepted answer allowed me to provide different urls without reloading the main controller.



app.js



var app = angular.module('myModule', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.

when('/items', {templateUrl: 'partials/items.html', controller: ItemsCtrl}).
when('/item/:itemId/', {templateUrl: 'partials/item.html', controller: ItemCtrl, reloadOnSearch: false}).
otherwise({redirectTo: '/items'});
}]);


Item.html




Foo


Bar






controller.js



function ItemCtrl($scope, $routeParams, Appts) {
$scope.views = {

foo: {name: 'foo', template: 'partials/itemFoo.html'},
bar: {name: 'bar', template: 'partials/itemBar.html'},
}
$scope.view = $scope.views[$routeParams.view];
}


directives.js



app.directive('itemTab', function(){

return function(scope, elem, attrs) {
scope.$watch(attrs.itemTab, function(val) {
if (val+'Tab' == attrs.id) {
elem.addClass('active');
} else {
elem.removeClass('active');
}
});
}
});



The content inside my partials are wrapped with ng-controller=...


Answer



If you don't have to use URLs like #/item/{{item.id}}/foo and #/item/{{item.id}}/bar but #/item/{{item.id}}/?foo and #/item/{{item.id}}/?bar instead, you can set up your route for /item/{{item.id}}/ to have reloadOnSearch set to false (https://docs.angularjs.org/api/ngRoute/provider/$routeProvider). That tells AngularJS to not reload the view if the search part of the url changes.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...