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.
Related
When i am using "location.href" in order to redirect to another view my current controller reinitialize. The both views are using the same controller. What is the better way to go between views but not recreating controller?
function onAddNewTest() {
//some logic here
location.href = '/#/testList';
};
route itself:
.module('applicationModule', ['ngRoute'])
.config(function ($routeProvider) {
$routeProvider
.when('/testList', {
controller: 'testController as vm',
templateUrl: '/Scripts/views/testList.html'
})
Try to use $location.path() in your controller like this:
function onAddNewTest() {
//some logic here
$location.path('/testList');
};
And don't forget to add dependency to your controller.
Hope it helps
I am using Angular and I need to define routing in ng-route config but also in my services to be used by $http in services methods.
The problem is that the route strings change in my application according to language ... For example for an about us page I might have:
"en/about-us", "pt/quem-somos", "fr/ ..."
The application has a RouteProvider that returns route strings by key.
The idea would be to create a script on the fly for a service that injected in angular components would allow to get those routes strings.
<script type="text/javascript">
// Create $routes service using backend code ...
</script>
This would be used on app.config as follows:
app.config(['$routeProvider', function($routeProvider, $routes) {
$routeProvider.
when($routes.getByKey('about.home', {
templateUrl: 'about/home.html',
controller: 'AboutController'
})
}
But also in a service as follows:
application.service('CountryService', function ($http, $routes) {
return {
GetList: function () {
return $http.get($routes.getByKey('api.countries.list');
}
}
});
My problem is how to write the JS part of such a service and to plug it into angular components. Is it possible to create such a service?
I would not conflate view routes from the API endpoints - these are different creatures.
And you don't need to create a route per language - just use language as a parameter:
$routeProvider
.when("/:lang/about-us", {
template: "<h3>About Us</h3> in lang: {{language}}",
controller: function($scope, $routeParams, $location){
$scope.language = $routeParams.lang;
}
})
.when("/:lang/something-else", {
template: "<h3>Something Else</h3> in lang: {{language}}",
controller: function($scope, $routeParams){
$scope.language = $routeParams.lang;
}
})
plunker
In my .config I have a router that instantiate a pair controller-router:
angular.module('reporting', ['ng', 'ngRoute', 'ngResource', 'reporting.directives', 'reporting.controllers', 'reporting.config', 'ngGrid', 'ui.bootstrap'])
.config(["$routeProvider", "$provide", function ($routeProvider, $provide) {
$routeProvider
.when('/dealersReq', {
templateUrl: 'reporting/partials/dealersReqs.html',
controller: 'DealersCtrl'
})
.when('/lmtReq', {
templateUrl: 'reporting/partials/lmt.html',
controller: 'lmtCtrl'
})
.when('/leadsCreated', {
templateUrl: 'reporting/partials/leadsCreated.html',
controller: 'LeadsCreatedCtrl'
})
...
but each controller share the same initialization code (think about it like a constructor) that sets in the rootScope some variable like a title and other useful information for some controllers outside the <view>:
.controller('DealersCtrl', ['$scope','$rootScope', 'CONFIG',
function($scope, $rootScope, CONFIG) {
//////////// duplicated code
var key = 'qtsldsCrtSncheQ';
$rootScope.openReport.key = key;
$rootScope.openReport.title = CONFIG.reports['' + key].title;
//////////// duplicated code
console.log('Initialized! Now I do what a controller should really do');
}]);
What I would like to do is finding a way to move that code - which is duplicated into every controller at the moment - into something smarter and neater. Soemthing that the route can call during the routing instanciation for example. Of course each controller should have a different key, but that one could be exactly the controller name actually. I really don't know how to improve this. Any suggestion?
Why don't create a method on the $rootScope which does that, and then call it from each controller, i.e.: $rootScope.init().
You could use a Service for shared code but you should avoid to use $rootScope
https://stackoverflow.com/a/16739309/3068081
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.
I am using route provider as follows,
var appModule = angular.module('ngLogin', ['ngRoute','restangular','btford.socket-io','ngSanitize','xeditable']);
appModule.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'sample/homepage.html',
controller: 'ngHomeControl'
}).
when('/contacts', {
templateUrl: 'sample/homepage.html',
controller: 'ngContactControl'
});
}]);
Here I need to call function from ngHomeControl to ngContactControl.
I tried as follows, but the function didn't invoked.
appModule.controller('ngHomeControl', function($scope,$routeParams,socket,Restangular,$http) {
$rootScope.$broadcast('getFriendList',{"userName":userName});
});
appModule.controller('ngContactControl', function($scope,$routeParams,$rootScope,socket,sharedProperties,Restangular,$http,$timeout) {
$scope.$on("getFriendList",function(event,data)
{
console.log('getFriendList');
});
});
Can anyone help me to resolve?
This will not work as only one controller is instantiated at a time (in your case).
A proper way would be to use a service. There is a nice article that wil help you with this.
See also this answer on how to create a service.
Based on those two resources you should came up with something similar to this:
var appModule = angular.module('appModule', ['ngRoute']);
appModule.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'home.html',
controller: 'ngHomeControl'
}).
when('/contacts', {
templateUrl: 'contacts.html',
controller: 'ngContactControl'
});
}]);
appModule.service('friendsService', function(){
this.getFriendList = function () {
return ['John', 'James', 'Jake'];
}
});
appModule.controller('ngHomeControl', function($scope, friendsService) {
$scope.homeFriends = friendsService.getFriendList();
});
appModule.controller('ngContactControl', function($scope, friendsService) {
$scope.contactFriends = friendsService.getFriendList();
});
There is a complete working JSFiddle so you can test it out.
Please also checkout the console output to see when used components are instantiated.
You will see that controllers are instantiated each time the route changes - they are instantiated implicitly via the ngController directive used inside templates. The service is instantiated only once and this is at the time when it is needed/injected for the first time.
The reason your event listener isn't fired is because there isn't a ngContactControl instance alive when your at /home. You can create a parent controller, which handles the scope events but a better way is to use a service that is shared among the controllers that need this functionality.
See this plunker for an example how to share data and/or functions via a service.