From f4517b500c0d2357d89e8c889f32f1466e5c1612 Mon Sep 17 00:00:00 2001 From: Braden Shepherdson Date: Fri, 19 Oct 2012 12:19:45 -0400 Subject: doc(faq): Add Common Pitfalls section Describes several common pitfalls new users of Angular fall into that I've observed in #angularjs. --- docs/content/misc/faq.ngdoc | 99 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'docs/content/misc') diff --git a/docs/content/misc/faq.ngdoc b/docs/content/misc/faq.ngdoc index e238b206..0e5d0b27 100644 --- a/docs/content/misc/faq.ngdoc +++ b/docs/content/misc/faq.ngdoc @@ -4,6 +4,8 @@ #FAQ +## Questions + ### Why is this project called "AngularJS"? Why is the namespace called "ng"? Because HTML has Angular brackets and "ng" sounds like "Angular". @@ -96,3 +98,100 @@ AJAX Apps}". ### How is Angular licensed? The MIT License. + + +## Common Pitfalls + +The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into. +This document aims to point them out before you discover them the hard way. + +### DOM Manipulation + +Stop trying to use jQuery to modify the DOM in controllers. Really. +That includes adding elements, removing elements, retrieving their contents, showing and hiding them. +Use built-in directives, or write your own where necessary, to do your DOM manipulation. +See below about duplicating functionality. + +If you're struggling to break the habit, consider removing jQuery from your app. +Really. Angular has the $http service and powerful directives that make it almost always unnecessary. +Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events. + +### Trying to duplicate functionality that already exists + +There's a good chance that your app isn't the first to require certain functionality. +There are a few pieces of Angular that are particularly likely to be reimplemented out of old habits. + +**ng-repeat** + +`ng-repeat` gets this a lot. +People try to use jQuery (see above) to add more elements to some container as they're fetched from the server. +No, bad dog. +This is what `ng-repeat` is for, and it does its job very well. +Store the data from the server in an array on your `$scope`, and bind it to the DOM with `ng-repeat`. + +**ng-show** + +`ng-show` gets this frequently too. +Conditionally showing and hiding things using jQuery is a common pattern in other apps, but Angular has a better way. +`ng-show` (and `ng-hide`) conditionally show and hide elements based on boolean expressions. +Describe the conditions for showing and hiding an element in terms of `$scope` variables: + +
Click here to log in
+ +Note also the counterpart `ng-hide` and similar `ng-disabled`. +Note especially the powerful `ng-switch` that should be used instead of several mutually exclusive `ng-show`s. + +**ng-class** + +`ng-class` is the last of the big three. +Conditionally applying classes to elements is another thing commonly done manually using jQuery. +Angular, of course, has a better way. +You can give `ng-class` a whitespace-separated set of class names, and then it's identical to ordinary `class`. +That's not very exciting, so there's a second syntax: + +
...
+ +Where you give `ng-class` an object, whose keys are CSS class names and whose values are conditional expressions using `$scope` variables. +The element will then have all the classes whose conditions are truthy, and none of those whose conditions are falsy. + +Note also the handy `ng-class-even` and `ng-class-odd`, and the related though somewhat different `ng-style`. + + +### `$watch` and `$apply` + +Angular's two-way data binding is the root of all awesome in Angular. +However, it's not magic, and there are some situations where you need to give it a nudge in the right direction. + +When you bind a value to an element in Angular using `ng-model`, `ng-repeat`, etc., Angular creates a `$watch` on that value. +Then whenever a value on a scope changes, all `$watch`es observing that element are executed, and everything updates. + +Sometimes, usually when you're writing a custom directive, you will have to define your own `$watch` on a scope value to make the directive react to changes. + +On the flip side, sometimes you change a scope value in some code but the app doesn't react to it. +Angular checks for scope variable changes after pieces of your code have finished running; for example, when `ng-click` calls a function on your scope, Angular will check for changes and react. +However, some code is outside of Angular and you'll have to call `scope.$apply()` yourself to trigger the update. +This is most commonly seen in event handlers in custom directives. + +### Combining `ng-repeat` with other directives + +`ng-repeat` is extremely useful, one of the most powerful directives in Angular. +However the transformation it applies to the DOM is substantial. +Therefore applying other directives (such as `ng-show`, `ng-controller` and others) to the same element as `ng-repeat` generally leads to problems. + +If you want to apply a directive to the whole repeat, wrap the repeat in a parent element and put it there. +If you want to apply a directive to each inner piece of the repeat, put it on a child of the element with `ng-repeat`. + +### `$rootScope` exists, but it can be used for evil + +Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree. +Usually this can be ignored, since most views have a controller, and therefore a scope, of their own. + +Occasionally there are pieces of data that you want to make global to the whole app. +For these, you can inject `$rootScope` and set values on it like any other scope. +Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like `ng-show` just like values on your local `$scope`. + +Of course, global state sucks and you should use `$rootScope` sparingly, like you would (hopefully) use with global variables in any language. +In particular, don't use it for code, only data. +If you're tempted to put a function on `$rootScope`, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested. + +Conversely, don't create a service whose only purpose in life is to store and return bits of data. -- cgit v1.2.3