I found that you can use template or templateUrl as a function like that
.when('/:controller/:action',{
templateUrl:function(params){
return: '/'+params.controller+'/'+params.action
}
})
And then I wondered if it's possible lazy load the template, but I can't make that work
.when('/:ctrl/:action',{
template:function(params){
injector = angular.injector(['ng']);
$q = injector.get('$q');
var dfrd = $q.defer();
// fetch template from server
// dfrd.resolve()
return dfrd.promise;
}
});
Tell me please there's a way - I want to fetch entire template by making ajax request to the server
As pointed out, templates loaded by templateUrl will be lazy loaded in normal circumstances, and there are methods of playing with the cache if you need something other than the norm.
This comment seems to be the crux of the matter:
I want to fetch entire template by making ajax request to the server
This is not necessarily a normal way to work with angular. It can have its usefulness, but it's off the beaten path. Usually templates are immune from everything that is context-sensitive because they represent code that gets its critical state information from $scope or parameters of some sort. So why ajax?
What does your template want/need that would come from an ajax request? The answer to that question may help with the ultimate decision of how to make it happen most efficiently and in the right place.
It may be that you want or need some server-side dynamism to be part of your system, or that there are other ways to do that than to have an ajax return defining the template.
Update: so you've said that 'On route change I need to get template from the server, asynchronously using $http".' But that's all built in to templateUrl. @wmluke seems to have presented some interesting alternatives.
If we just accept that you need ajax to get your template, then here's one more possibility. With ui-router you can use a templateProvider -- which could call you own custom service that does ajax and whatever else you want.
This example just returns Hello world asynchronosly, but you could call your own service here or directly execute ajax requests if you wanted to.
templateProvider:
[ '$timeout',
function ($timeout) {
return $timeout(function () { return "Hello world" }, 100);
}],
Buying in to ui-router is a potentiall bigger commitment, but it might yield rewards above just being able to write code to produce templates. Good luck!
So, I see you're a .NET MVC developer...
Let's have a look at what Actions do in .NET MVC: They return ActionResults... which are really manifests for what view and model should be ran and returned from the architecture. A "controller" in MVC is a collection of such actions, and may contain some shared logic between those actions in the form of private methods or shared dependencies on that class.
Now let's have a look at what Angular is doing: Angular is calling the controller function one time, as a constructor, generally to set up a $scope object which will act (sort of) as your "model". Every controller in Angular is (generally speaking) associated to one and only one way to set up a $scope**. Once that controller is processed, a $digest is called on the $scope it altered, which is then applied to a the view that is bound to the scope... which is the html encapsulated by the element with your ng-controller (or ng-view) attribute.
So.. the question, can you dynamically load templates based on route parameters? Yes. You definitely can. The easiest way would be to route your requests to a single template that included nothing but a div with an ng-include
on it, that you changed.
In your routes:
$routeProvider.when('/:controller/:action', {
controller: 'DynamicCtrl',
template: '<div ng-include="include"></div>'
});
Then your dynamic controller declaration:
app.controller('DynamicCtrl', function($scope, $routeParams) {
$scope.include = $routeParams.controller + '/' + $routeParams.action;
});
MyController/MyAction (which I assume you may be generating with Razor) should return something like this:
<div ng-controller="MyActionCtrl">
do stuff!
</div>
... from there you would define your MyActionCtrl controller all to itself.
Can you bend the architecture to make it "ASP.Net MVC-esque", in that "one controller" has a whole bunch of "action" functions in it that dictate the entire behavior of your view? Yeah... But not without making your application really silly with switch statements and the like... So you probably don't want to do that.
In the end you're going to have to get out of the mindset of ASP.Net MVC's "Controllers and Actions" with Angular. It's an MVC architecture, but MVC != "Controllers && actions".
** Angular also creates and saves an instance of the controller as an object too, but that feature is rarely used in Angular development, and I'm not talking about that here, per say.)
Why not just bypass templateURL
all together and have your controllers intercept the requests?
You will be able to dynamically lazy load pages by URL
Optionally intercept partials.
config.js
$routeProvider.when('/contact', {
template: '/views/contact.html'
});
controllers.js
controller('AppController', ['$scope' function($scope) {
//Do whatever you want here
$scope.$on("$routeChangeSuccess",function( $currentRoute, $previousRoute ){
console.log($route.current.template);
$scope.page = $route.current.template;
});
//Optionally intercept partials
$scope.returnView = function(partial){
console.log(partial);
return partial;
}
}]).
index.html
<html lang="en" ng-app="myApp" ng-controller="AppController">
<body>
<ng-include src="returnView('/views/global.header.html')"></ng-include>
<ng-include src="page"></ng-include>
<ng-include src="returnView('/views/global.footer.html')"></ng-include>
</body>
</html>
Angular templates are lazy loaded by default. Specifically, templates are not fetched until they are needed and then they are cached in $templateCache.
However, based on your example I suspect you're looking for the resolve
attribute for route definitions in $routeProvider. This attribute allows you to pass promise dependencies to a controller. See the delay example in $route...
$routeProvider.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: BookCntl,
resolve: {
// I will cause a 1 second delay
delay: function($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
});
Also, you might be interested preloading some templates but lazy loading others. In this case you should check out...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With