My love affair with AngularJS
redbeacon.github.io
redbeacon.github.io
Another gripe I must bring up with Angular is the lack of proper tools. Batarang has not updated for 7 months and it leaves so much to be desired for debugging with the Angular framework (especially when viewing bindings). Irregardless, these small pains I feel toward Angular are worth trading in the greater pain I feel from Vanilla/Jquery JS development.
[1] http://cliffmeyers.com/blog/2013/4/21/code-organization-angu...
I build based on features, with all the code and tests of a feature placed together, with any shared dependencies lower down in the directory structure.
Heh, I'm just imagining code bubble up :P
Though that's definitely a wrong way to think of it since it's a call tree, but it always bugged me that in JS, you'd have to download dependency code you might not use (hence important code "bubbles up"). That's why I'm intrigued to try Dart for it's "tree-shaking" compiler that removes unused code from dependent libraries.
I forgot to add, I will also create a directory tree for singular service dependencies, so that a service can have multiple, non-shared, dependencies that are each considered a 'feature' and consequently have their own folder containing their code and tests.
I need to blog this, but node is fighting with osX on my macbook right now. I am not a happy camper.
The most important question is "can I quickly guess what directory this directory lives in?"
When you come across directives that clearly feel "utility", you will be tempted to look in a utility folder. When a directive is something tightly coupled to a feature, you might be tempted to first look in the directory related to that feature.
I tend to agree, and this is how I'd organize a larger Angular app, but to be honest I don't think it makes a huge impact in the long run. Rails apps are divided into dirs for models/controllers/views/etc and while I would rather have them organized by feature, they're still easy enough to navigate with modern code editing tools. It's certainly not one of the main contributing factors to how horrible big Rails apps get...
Then the controllers.js file only handles the routing controllers, and the html for each route is built solely out of components.
I resisted using require at first because it seemed like clunky cruft on top of Angular's cruftless dependency injection, but I was wrong and this way of working has been a lot of fun, relatively stress free and great for new devs since they just need to get their head around the way a component is put together and they never have to worry about other parts of the app.
The credit for this stuff has to go to a guy called Tim Kendrick whom I work with. He set up the project that my project is based on. He figured out the project structure and I've basically copied it with a few minor adjustments.
https://github.com/tnajdek/angular-requirejs-seed
You can structure the app however you want, but I would suggest having a component directory which is structured like this...
---------
src/js/components
|- myComponent
|- myComponent.js
|- myComponent.html
|- _myComponent.scss
---------Then you need an extra module that you inject when you're defining your app. This module is responsible for injecting all the components you want to include, here's a Gist
https://gist.github.com/gargantuan/8902061
So every time you create a new component, you have to require it in components.js AND you have to include the sass partial in your main .scss file.
On the subject of sass, you'll need to prevent sass files being included more than once. Fortunately 'courtismas' has a solution for that
https://gist.github.com/courtsimas/1167053
Other notes:
I'm using Gulp for my build tasks. I can't recommend it enough. I'm looking into creating a Gulp task that will generate a JSON manifest of components so new components are automagically included in the app. That way there's no need to manually maintain the sass and components.js files.
if you select an element in DOM inspector in Chrome,
its scope will be accessible via $scope in the console
Another trick that I use daily: to get a reference to some service(or anything injectable for that matter) from the console: angular.element(document).injector().get('myService')I have a strong suspicion that all of these Angular diehards have never worked on someone else's Angular project.
That said, I've worked with other people's angular code and I can't say that refactoring other people's implementations was a problem.
However I can see how a someone without a proper understanding could make a mess of things, particularly if they are also bad at TDD.
As for your bad experience, I can see how that can happen with Angular, but I can also see that happening in other ways with other libraries. In my opinion that is solved by using good code patterns and writing code for others, not for yourself. I'll leave this relevant quote:
"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." - Martin Golding
But from my perspective, I'd rather inherit a messy AngularJS project rather than a messy jQuery project. Or Backbone. With jQuery or Backbone, who knows what kind of stack they decided to use, or what kind of crazy hacks they implemented to get it to work? The same thing can happen in AngularJS, but at least it is more probable that they'll be relying on out-of-box tools for core functionality.
Now, I agree that in general, web software front end projects can be gross, but I find Angular to be the least gross solution.
Angular isn't a cure-all for good application design. You can write bad Angular code as with anything else.
That being said, as I've spent more time programming, I've shifted my preference towards frameworks that don't impose specific structures on you. This is mostly because forcing one structure gives you little flexibility or wiggle room if that structure doesn't fit great with your app, which you can already see other comments here pointing out. If you are working on a project with a team, all you need to do is meet before the project starts and decide on an organizational structure that you are going to use to gain the same results with any framework (and as another comment mentioned, also being able to avoid the fact that angular shoves way way too much logic into the html where it absolutely does not belong, and will quickly get out of hand in larger and/or more complex apps).
If the next step after "decide on a structure" isn't "WRITE IT DOWN", the maintenance devs who follow after you are going to curse your name.
You've got to be joking. An Angular "module" is a chunk of code that happens to be given a collective name. There's no namespacing, no encapsulation, and no build/file management.
Perhaps you're thinking of another language's definition of modular?
When "modules" can break each other because of purely internal implementation details, there is something very wrong.
So the Angular approach is modular, but slightly broken.
I really think the whole idea of a global name-based registry is flawed. Again, look at more traditional library/class-based language like Java, C#, and C++ - they have to go to absurd levels of verbosity, and don't even get absolutely guaranteed uniqueness out of it, but the power of dynamic linking makes it worthwhile.
You don't really need to for angular development. Namespacing Javascript is a cargo cult practice brought over from more traditional OO languages.
> no encapsulation
There is if you want it to be. You're especially encouraged to separate the concerns of the DOM in directive services, for example.
> no build/file management
That's kind of up to you, isn't it? You can run with grunt/require if you want a headache, grunt or gulp / uglify if you want easy, you can run with gulp/browserify if you want the new cool ...
You're right about services providing encapsulation. I still wind up with a lot of awkward situations where directives can't work without knowing something about their parent scope. It's possible that's more my problem because it's getting less frequent as I abuse ng-model more and more, but also remember that isolate scope, up until very recently, worked in an incomprehensibly stupid way [1].
>grunt or gulp / uglify if you want it easy
Eh... not really that easy. At least, not if you want to anything more sophisticated than concat together every .js file in sight. Require, for all its problems and relative-path headaches, at least makes it dead simple to run in development without having to remember to either add another file to the list or wait for a rebuild every time you change something.
[1]: https://github.com/angular/angular.js/commit/909cabd36d77959...
"Rightfully so, because I would have destroyed the DOM that Angular was using as its template. Angular doesn't use string-based templates; it uses the DOM itself."
Up until now, string based templates have been far better performing. Using the DOM as a template engine has been clumsy and laced with oddities. (ng-cloak) Not really what it's designed for.
Everything seems to be either written as code (URL handling) or coded into the DOM. Do I really want my HTML to be Angular specific?
I also like this about the article:
"Another way to look at Angular is to give it the sheriff's star in the cowboy land of frontend development. The lack of official documentation and the ever decreasing differences between browser implementations groomed a culture of "whatever gets the job done."
Then he proceeds to write:
"The documentation leaves a lot to be desired, because it's sometimes incomplete or out of sync, leaving the actual source code as the only source of truth. Now this is not cumbersome for an experienced engineer, but it's daunting for a new engineer to even read, much less understand. The Angular source code is not the most straightforward implementation."
So, Angular's got that going for it.
String templates outperform DOM, this was very true in the past and as far as I know still is true. The great advantage of it, is the "live" data bindings, which I think depend on the template being the actual live DOM. (I can be wrong here, and if I am then I need to go learn more about this choice)
As for the documentation point, you are right I contradict myself. What I meant to say is that angular suggests a way to structure your application versus backbone for example that only gives you the tools and no structure.
Thanks for pointing these out, I'll have to be more careful on how I express myself next time I write something.
This definitely seems to be the direction everything is going with web-components.
In Backbone you had very rigid definitions of models, collections and relationships between them, whereas in Angular any JS object can be a model and relationships between models can also be very flexible(although scope hierarchy is something u need to wrap your head around).
The documentation does leave a lot to be desired and I often find myself going back to the 1.1.5 directive documentation to look up different scope data binding options etc.
Just to address a point made towards the end of the blog, we do realize that Angular is not a flawless framework, and we are absolutely open to hearing feedback from users of the framework, get your bugs fixed, and ship some elegantly structured, easily testable code.
We are making an effort to do a better job of communicating with our users (apart from the big internal apps). This can be seen in the new Angular community working group, as well as my own and Pawel's frequent activity on the IRC channel and mailing lists. So let us know what your issues are. And if you have time, take a stab at implementing a fix, too. Community contributions are welcome.
xD (For clarity I'm attempting to be funny in this comment)
Also, I feel like their example is better served as a filter, rather than a directive.
After you wrote about my example, I realize that you are correct, it was not a great one. My bad!
Take a look at the Google Trends for the leading contenders: http://www.google.com/trends/explore#q=angularjs%2C%20emberj...
It's mind-boggling how much farther ahead angular is. Then again, angular is pretty awesome and have been a big fan for over a year now.
With 'js': http://www.google.com/trends/explore#q=backbone%20js%2C%20an...
Search trends do indeed, suck.
(edit: good responses, thank you)
Ember: http://emberjs.com/ember-users/
Angular: http://builtwith.angularjs.org/
http://www.google.com/trends/explore?q=angularjs,+extjs,+emb...
As for arguments that popularity doesn't matter, well transferable skills do matter and ecosystems and communities do.
I Googled about 30x more frequently when using Angular.
https://github.com/search?q=Angular&type=Repositories&s=star...
The organization that has worked for me (at this scale) can be seen at: https://github.com/filearts/plunker_www/tree/master/assets/j...
Organizing by feature, while great on the surface, is a challenge when the majority of code is designed for re-use anywhere in the app. As a result, each file is its own module in Plunker. In the WIP rewrite you have modules like "plunker.directive.aceEditor" that will contain a mix of directives and services necessary to interact with the ace editor in the Angular world. In this sense, you could say that code is organized by 'feature' if feature is very narrowly defined.
Understanding a body of code under this approach is relatively simple since the modules required by a given module must be listed for Angular's DI to work. The required modules' names correspond directly to the physical location of the code so navigating is pretty simple.
That being said, there is still lots of room to improve and Plunker is by no means a 'large project' (it is made by a team of 1 person).
For the record, I've found the documentation to be quite good. Read the guides and understand how it works before you get going, and you'll be able to reason about its behaviour without much trouble. The source is very well documented as well.
Might be a problem for a LOB that people might use everyday. maybe using read-only bind directives would make apps more responsive.
The delay is actually related to one of two things (I've profiled pretty heavily)
1. When moving between cards (in the card view), the render is very expensive. The code runs in about 50ms, which could be faster, but is good enough to feel responsive if rendering were not an issue.
2. When searching, laying out the grid is, again, very expensive to render. I've cut out Angular from all except for event handling. The grid items themselves are read-only bound (although the collection watch still exists), and I rearrange their position/visibility through CSS. This is, in my opinion, not a fault of Angular's. The other frameworks wouldn't fair too much better.
It certainly feels way more responsive than any non-single-page-app in my experience.
The single page apps I use every day are mostly GWT apps (namely Gmail & co), and comparing those to angular, I'd say angular has the lead (though that's not exactly a fair comparison, maybe GWT could be just as responsive). Don't know how it compares to other frameworks.
Obviously native applications usually still beat web apps in that respect (tho the gap is getting smaller).
One of the core issues with angular is maintainability imho. There are few best practices and almost no documentation on proper project layout. You can also build an application any which way you please. Want state in your controller? Sounds good. Want to build an app with nothing but directives? Sure. Inline all your HTML into your directives? yes please. Hell, in theory you could build an entire site out of comments using 'M' type directives. Of course the code base will be a bit of a mess - but it still makes great eye candy.
Another issue with angular is that you're frequently doing a deep dive into how angular is built. Want a recursive directive built in the compile phase? Uh oh, my screen locked up. Pass a '&' scope method into a nested directive? Hmm, does angular wrap that in a getParent()?? Do I need to double bind the parent callback using '=' in the nested call? There is WAY to much need to understand the compile and link phase. My unit tests for $q promises don't fire because they only resolve on a $digest cycle? Uh, how does that work again?
It's a great attempt to build a front end MVC. It definitely speeds up development time and it enforces the IDEA of testing your javascript at a least (a concept foreign to most jquery developers). However, it's still miles from being an ideal front end framework imho.
Were building something like shopify dashing, but with Scala and, possibly, angularjs.