-
Notifications
You must be signed in to change notification settings - Fork 3k
More scalable examples? #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
P.S. I should add that I'd be more than happy to contribute to the sample project/docs as a result of anything learned here! |
I'll take a crack at the controller question. Hopefully if I'm off someone will correct me. https://github.com/angular-ui/ui-router/wiki/State-Manager shows in its simple example that the traditional ng-controller="MyController" still works (at least if it's provided in a parent view). https://github.com/angular-ui/ui-router/blob/master/src/viewDirective.js#L2 confirms that $controller is a dependency of ui-view. So you could leave it up to the HTML and injection, where controllers are defined like: angular.module('app').controller('MyController', [ ... |
That makes sense. I really liked the idea of dropping the ng-controller attribute, but if that's not an option it's not really a deal breaker. |
We're using it for a relatively large application now and absolutely loving it. Our app is made up of many mini-apps with states being derived in each different "mini-app". Absolutely adore this resource, I hope one day it replaces ng-view in core :) |
as @sparko says, you can define your controller using $stateProvider
.state('report',{
views: {
'graph': {
templateUrl: 'report-graph.html',
controller: 'MyCtrl'
},
}
}) |
I completely missed that that was an option, thanks for pointing it out! |
Apart from using standard controllers, scaling is also related to the ability to load component code - controllers in this example - on demand. Otherwise we need to download all of our controllers on the first page. This is an Angular core question - but still, wondered if any one has any idea regarding it. |
@uberspeck could u reopen for the scalability discussion? i believe its important. thanks |
thanks. repeating... |
This 3 part article was mentioned on G+ today. It might contribute to the conversation... |
thanks for this article. This definitely addresses the subject from a build/folder structure perspective. The biggest deficiency of Angular, in my view, for large scale MVC apps, is the lack of on-demand loading of Controller and Models. On the View front, ui-router leads the way for dynamic loading - that's why its such a great project. i'm trying to think how to address the M and C and whether it could be done within ui-router This, by the way, is related to the second biggest deficiency: server-side rendering. the new Rendr project of backbone.js shows the need of bootstrapping from pre-rendered HTML. connect-prerenderer shows a nice full-page-based bootstrapping idea, but for public facing sites, where some areas are personalized (i.e. you want your login link to show as Not Lior? link to the user Lior), we need the ability to load some directives on demand while keeping others bootstrapped from the html snapshot |
For lazy loading controllers, here's how someone has done it (using requirejs and the core router/routeProvider): http://github.com/jensaug/angularjs-requirejs-lazy-controllers That code seems to boil down to "download and register the controller by name using requirejs within the resolve promises of the route definition". I haven't yet wrapped my head around how or if this could be applied to ui-router as is. EDIT: this discusses the issue: #104 |
@lmessinger, unfortunately I haven't much to contribute on either of the deficiencies you mentioned. I last looked at on-demand resource loading several years ago...before the javascript "revolution" we're seeing now. There weren't a lot of tools for it then and what existed was buggy. I dropped the approach then and haven't taken the time to revisit. I admit it would be really nice to see that baked in to Angular. |
thanks! the approach by jensaug is very helpful. someone on the list also sent me http://ify.io/lazy-loading-in-angularjs/ - i think it also takes a similar approach although still havent delved into both |
I just came across this one: https://github.com/szhanginrhythm/angular-require-lazyload for requirejs lazyloading. Again using promises. This one seems a little cleaner/organized/complete. |
Converting Angular-app to ui-router would give us a clear understanding of ui-router. Putting everything in a single page for a demo is not very helpful. |
So the fact that
is a possibility, is great. It should be mentioned in the docs though -- it wasn't clear to me either and I was looking for an example with more than a single js file / block as well. ++ to mention this in the docs at https://github.com/angular-ui/ui-router/wiki/State-Manager |
@bf0 example added |
I've implemented a provider/service to lazy-load/lazy-register components using AMD. It works with the stock router. I'm trying to get it to work with ui-router and thus far no luck. The stock router resolves the entire route definition as a promise. Since the state provider needs some of the properties right away (the url property in particular), I tried to trick it into running the couchPotato lazyLoad function within the resolve property by using a dummy property. So, with the stock route provider, this code works:
I haven't yet found a way to get anything similar to work with ui-router. Granted, I just started trying, but my initial test suggests that the code running under the resolve property is evaluated at run time, not config time, and thus a service rather than a provider is required. The $couchPotato service also has lazyLoad defined, but it doesn't seem to be called the way I'd hoped. So this doesn't work:
If I figure out a way to make it run the lazyLoad function, I'll post back. If anyone knows how, I'd appreciate a tip! Essentially all I need to do is force it to run the lazyLoad function when it's activating the route (and before the router or the ui-view directive try to invoke the controller). |
This is couchPotato (derived from the examples linked above). https://github.com/afterglowtech/angular-couchPotato . I'm not finding a means to get it to run under ui-router. |
It would be pretty simple to allow a promise for 'controller', as 'template' and 'resolve' need to be loaded asynchronously anyway -- currently 'controller' is just statically shoe-horned into the output of 'resolve' as a magic '$$controller' property that ui-view picks up. In fact you should simply be able to resolve the '$$controller' property manually inside 'resolve' (and just leave out the outer 'controller' property) and it should work. |
Thanks, @ksperling. At first glance it doesn't look like I can override $$controller, since
However, this begs the question of why the controller that I intend to have registered by the time resolve() is finished isn't being picked up. I'll try to debug that later today. It may be that the my lazyLoad function isn't working properly when called on my service (as opposed to my provider). I woke up realizing that I should refactor it a bit anyway. Hopefully I'll end up with something that doesn't require anyone to write the word "dummy" in their route configurations. The ideal for what I'm trying to do would be to have a property that is generically resolved without any particular assignment of its result back to a "real" configuration property... but if people need to assign undefined to an unused/fake property it really won't hurt much. No biggie. :) Hopefully I can make it happen with ui-router as is. |
ui-router is expecting the promise function, not an object that contains the promise function. So this code works now.
and here's the project for those who wanted to do lazy-loading in ui-router (it will lazy load/register controllers, directives, services, and filters -- see the sample and sample-ui-router directories for examples -- I need to make better instructions but that may need to wait till tomorrow). https://github.com/afterglowtech/angular-couchPotato Hopefully that's one nibble off the subject of scalability (which this thread was supposed to be about). Please refer any questions about it over there... I think @nateabele may have cooked up a way to dynamically register modules, and I'd like to look into how that could fit into this scheme soon. ...and now we can go back to more scalable examples here. |
This is not actually working for me, it's not super clear why my registered controllers are not able to be instantiated. I've checked in the code, but it's not too clear just from reading what $$controller is, or how actual controllers are instantiated. A small splash of the code looks like this: angular.module( "chineseCommunityApp", ["ui.bootstrap", "ui.compat", "ngResource"] )
.config([
'$stateProvider',
'$urlRouterProvider',
'$locationProvider',
($stateProvider, $urlRouterProvider, $locationProvider) ->
$stateProvider
#
# State shared by the entire application
# - Always render header
# - Always render footer
#
.state 'app',
url: ''
abstract: true
views:
'header':
templateUrl: '/views/header.html'
controller: 'HeaderCtrl'
'footer':
templateUrl: '/views/footer.html'
controller: 'FooterCtrl'
# Event routing
# Event is considered the "default" resource of the site,
# and as such the root of the module is used
#
.state 'app.events',
url: '/'
views:
'container@':
templateUrl: '/views/event/list.html'
controller: 'EventListCtrl'
# ... And, since this app has only recently been migrating to Angular/Angular-UI, only the EventList has been implemented: angular.module("chineseCommunityApp")
.controller("EventListCtrl", [
'$scope', 'dataService',
($scope, dataService) ->
this.events = dataService.events
$scope.events = this.events.query()
]) So, the 'header' and 'footer' views are just dandy, and their controllers are found. However, the 'container' view has some difficulties. Chromium and FF25 report the following:
The script containing the EventListCtrl is included later than the script containing the app routes, but it's still not clear to me why it's claiming to be undefined. I really don't see why that would be the case at all :( This is, for me, a very big headache which I've only been able to resolve by squishing everything in a single script -- clearly that's not acceptable, so I'd like to figure it out. After searching for resources for nearly 18 hours now I'm just about ready to give up and resort to squeezing everything together in a hideous mess. This is with release 0.0.1, I'm not sure if it's worth trying a bleeding edge version just to see if this can work for me in the future. I know this isn't tech support, but I would be really curious to see what exactly the issue here is ._. |
Couple things to test... So your index has a header, footer and container ui-view? Try adding the controller as an anonymous function in the state config, just to make sure that works. Last make sure this isn't the bug, check the FAQ for resolution to that one. |
Correction: ...isn't the |
I'd be happy to help you debug your code if you reposted it as actual JavaScript. |
@timkindberg sorry, yes, the index template has: <header ui-view="header"></header>
<div ui-view="container" class="container"></div>
<footer ui-view="footer"></footer>
In the case of edit: I will test adding the controller as an anonymous function, but there are quite a number of these unfortunately, it won't really work if that's what I end up having to do app-wide :( edit again: Yes, as an anonymous function it works perfectly. but as I've said, I can't really do that for this app and expect my client to be happy with the results ;_; I don't believe it's as you call the @nateabele I can provide code translated from js2coffee, but it does produce the expected code and I feel that it is somewhat more readable in coffee-form. Here: angular.module("chineseCommunityApp", ["ui.bootstrap", "ui.compat", "ngResource"]).config([
'$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
return $stateProvider.state('app', {
url: '',
abstract: true,
views: {
'header': {
templateUrl: '/views/header.html',
controller: 'HeaderCtrl'
},
'footer': {
templateUrl: '/views/footer.html',
controller: 'FooterCtrl'
}
}
}).state('app.events', {
url: '/',
views: {
'container@': {
templateUrl: '/views/event/list.html',
controller: 'EventListCtrl'
}
}
});
}
]); and angular.module("chineseCommunityApp")
.controller("EventListCtrl", [
'$scope', 'dataService',
($scope, dataService) ->
this.events = dataService.events
$scope.events = this.events.query()
]) |
Oh, hey, crisis averted. Apparently I'm an idiot and was not uglifying+concatenating the script with the controller in question, even though I could have sworn that it was in the processing list. Well I feel dumb now! But at least things are working. |
@caitp What are you using to build your solution?... If you have a structure to your scripts, you can often use wildcards to make sure you always collect on all your scripts... All you need to remember to do is make sure your modules are defined before you try to add things to them...
In many build systems you should be able to do something like:`
This is largely possible because angular works as it does, so even if "ControllerA" is defined before "ServiceB", yet it uses that service, it will still work. Just a tip :) |
It's grunt-contrib-usemin, it only operates on files it finds in marked blocks on template files. Not totally ideal for dev builds, but I'm preoccupied with other things to be worried about it right now. I could have sworn that I had renamed the script in the block, but I guess it's easy to miss and I felt really stupid because of it :) I'm just really glad it wasn't a bug with ui-router because that would really ruin my friday! |
@caitp well your not the first one with the famous "I forgot that file" or similar, I think it's safe to say that we have all tried it before, and will all experience it again, so hence the suggestion/tip to at least eliminate some of it... :-) I don't know if it's possible with the grunt-task your using though. But hopefully you will be able to find a solution, ones you have your hands more free, that won't require you to manually maintain lists of files in the future :)... |
@uberspeck @stu-salsbury @SparkiO @jeme @lmessinger |
Here you could find my proposal. The solution is based on ES6 modules |
First, thanks for the excellent resource! I'm looking forward to using it on a major application rebuild. Just trying to wrap my head around it now ;)
Wondering if someone could give examples demonstrating how ui-router might scale to much larger applications (than the sample app for example)? I'm fairly new to Angular and just started reading up on ui-router. The sample app demonstrates everything in a single JS file. How might I proceed if my JS is spread across separate files (appConfig.js, appController.js, usersControllers.js, accountControllers.js etc). Can I pass my controllers to config using dependency injection? Defining them all inline isn't very feasible for a project of this size and I'm trying to keep things separated as much as possible for maintainability.
The text was updated successfully, but these errors were encountered: