AngularJS Best Practices: Understanding UI-Router & ORM
Codementor AngularJS expert Dean Sofer is a full-stack developer who has been working with Angular since v.0.9.x before it was even popular. When the framework started to take off, he founded AngularUI for AngularJS to make life easier for other people.
Dean has given talks at conferences and Google on best practices, and he recently sat down with us during open office hours to answer some AngularJS questions our viewers had.
The text below is a summary done by the Codementor team and may vary from the original video and if you see any issues, please let us know!
What are the Current Best Organizational Practices of AngularJS?
Wouldn't you end up with hundreds of overlapping modules and a massive project.shared module if you go down the ORM route?
I’ve been pretty lucky as my projects have been large but not Google conglomerate large, so my projects have always remained pretty compact. However, I’ve been rethinking my attempts to nest the folders, and I get that you need to reuse things in different places. Therefore, I don’t have a good suggestion on how to address this problem right now, but one of the things I’d do is reappraise your shared module and see if that can be broken up. Instead of having all of your external module dependencies declared at your root app level, the user module in its module declaration would declare what services, utilities, or plugins it would need instead of putting it on a top level.
What are Some Resources You’d Recommend from Angular UI?
Angular UI has many different directions. It used to be one suite, but it got so big we split it up into multiple projects and it became an organization. UI-Router is hands down my favorite project, as I think it’s the most valuable part of Angular. I used to be a lot more into UI bootstrap, but now it’s a bit of an ambiguous situation because of maintenance issues. People only use their free time to do the project so it has been falling a little bit behind. I’ve been a little unimpressed at how the directives have been implemented at UI bootstrap so in that aspect I don’t recommend anything except your simple HTML logic and CSS classes.
Additionally, the Angular UI utility suite is pretty neat, as it provides things such as much richer validation. You can add multiple custom validation rules by simply declaring a function on the scope, you can use promises in your validations, and you could quickly slap a jQuery plugin onto the page in a couple of seconds. We tried to build it as a basic building block that other people could stack together into other tools.
How would you compare UI-Router to Ember?
I’ve personally not worked with Ember at all, but I know UI-Router takes a ridiculous amount of inspiration from Ember. Still, while Ember puts a large focus on URLs, in UI-Router, URLs are like aliasing and shortcuts. UI-Router is more like a state machine, or the basic building blocks of the structure of your applications, and the URL is a decoration on top of the state machine.
I think the state machine is a lot more resilient and stronger/versatile in the long run, which is why I recommend having different modules, as they could be mapped out to the UI-Router state machine. When you think of them as states, you can map any of these modules to any URL you want. However, you can build an entire application without any URL, so it is unnecessary to the UI-Router. All you’d really lose is the ability to refresh your page and pick up what state you’d left off, but you could still move around the system. Personally, I like being able to have that distinction, as I can break down my app even more deeply than simply changing the URL. Of course, there’s also no reason why I can’t have the URL reflect my changes, but I like not being limited by it.
What I’d do is drop all concerns of URLs when building an initial prototype, and then come back in to treat the URLs like a convenience. Every single state could have a “vanity URL”, but it doesn’t need to. The only time URLs are important is when you need parameters from them. I always build my states first and come back to tweak the URLs later. Finally, remember you can always alias your URLs so don’t build stupid module structures just to get the URL you want.
If you’re worrying about where the back button will lead you to, this should be tackled separately from the project structure, as it’s the worst thing to think about when you’re breaking down an application. You should break down an app based on structure, which is what ORM’s all about—modularizing and breaking down the app. Thus, What you’d really want is a feature that manages the URL history instead of letting it dictate the project structure. I actually don’t focus on the back button. I mostly determine whether I want this state to be accessible through URL or when I refresh the page, where I’m landing. I make sure the transitioning in and out are done correctly, and I make sure needed assets will carry over. For example, if I go from state 1 to state 2, would the data I needed from state 1 not get loaded in if I refresh and jump state 2? That sort of reasoning is sorted out and done by results, but worrying about the back button and forward button hasn’t been a problem for me.
How Would You do Tests in your ORM Projects, and Where Would You Organize Your Controllers?
I’ll be honest here—tests are not my forte. One of the things about the ORM project I might change now is that I might not nest it all. I know all the code in my project is testable, as I’ve written tests around code like this before.
If you have huge controllers that are difficult to test, you may want to look into using ORM to organize your projects. My project makes a huge emphasis on what I call classes, or CoffeeScript classes. You don’t have to use classes—they’re just factories. If you look at my project module and open project.coffee, you’ll notice I have a project object around line 59. This whole project has objects, and they’re CoffeeScript classes, which end up being simple prototypes. I’d tell people to put 90% of their logic in the factories/classes, and 9% into a state machine. You’ll find your controllers will only end up taking up 1% of your logic, where it’s just taking stuff and putting it on the scope or taking stuff off the scope.