Over years of building Angular 1.x projects, and trying out recommended best practices, I came to realize that some things just weren't working, and there was a better way. The following summarizes my observations and new recommended best practices which I have personally used and can vouch for their efficacy in reducing defects and increasing development velocity and maintainability. Comments and PRs are welcome.
- Separation of concerns -- html templates, js services.
track by
inng-repeat
. Lack oftrack by
inng-repeat
expressions is the primary source of all complaints about angular performance.- $scope
- $scope handles user input and asynchronous events very well. It requires
some work (
$apply
, etc.) to handle non-angular asynchronous events, but this is intuitive and well worth the cost.
- $scope handles user input and asynchronous events very well. It requires
some work (
- Services
- Singletons provide easy access to data and shared functionality.
- No reasoning about instances.
- No babying object references if all references are fully-qualified.
- This is a problem you encounter when you write
$scope.data = MyService.data
in a controller, then later replaceMyService.data
somewhere else, e.g. after an $http get to update the data).
- This is a problem you encounter when you write
- $http
- Directives
- Declarative reaction to user input events or model updates
- testing; no-fuss methods are provided by Angular 1 to help set up test cases
$scope
events.- Angular "Controllers"
$scope
is the controller in Angular. It reacts to user input or async changes in the data model, binding the UI and data together.- Input events should directly trigger logic in well-known and visible services.
- Using event systems. This seriously inhibits predictability and the ability to causes additional bugs, because you don't know who is broadcasting or listening to events.
- Building complicated service hierarchies or relationships.
- Instead, the relationship should be made obvious in the template. E.g.
<div class="username" with-service="{f: 'MyFriends', rp: '$routeParameters'}">{{ f.byUsername[rp.username] }}</div>
- Instead, the relationship should be made obvious in the template. E.g.
- "Components" as replacement for native HTML elements.
- Directives should very rarely use the element type, opting for augmenting the behavior of native HTML to avoid creating tribal DSLs.
- A new directive that supports explicitly importing services into angular templates.
- Effective deprecation of "Controllers." Much more often than not, these add a layer of obscurity and end up taking references. This might seem to clean things up, but it creates bugs when the references become stale.