Where my docs at? (A smattering of pointers on AngularJS, one of which at least is difficult if not impossible to find on the Internet)

by

AngularJS is a young framework, still so downy-soft that much of the advice you’ll find on support forums refers to an earlier and almost completely incompatible minor version.

So long as you don’t hit a blind spot in the documentation or the community support, it’s a great framework for rapid development, but as soon as you try to do something that isn’t public knowledge, you’ll be scratching your head for hours.

For the greater good, then, I offer these little tips (I’m using Angular 1.0.1):

Change the Location without changing the Route

Oftentimes in a single-page app you’ll want to update the location bar for bookmarking or history purposes, but manually managing your application state. Angular doesn’t explicitly offer a solution for this case: by default all location changes go through the routing process, which updates the angular view.

There’s a simple way to short-circuit this, however. Angular watches for a location change (whether it’s accomplished through typing in the location bar, clicking a link or setting the location through $location.path()). When it senses this change, it $broadcasts an event, “$locationChangeSuccess,” and begins the routing process. What we do is capture the event and reset the route to what it was previously.

function MyCtrl($route, $scope) {
    var lastRoute = $route.current;
    $scope.$on('$locationChangeSuccess', function(event) {
        $route.current = lastRoute;
    });
}

 Watch out for implicitly created scopes

In addition to scopes that are explicitly created when you tie a DOM element to a controller, Angular automatically creates a scope when you use ng-repeat, ng-include, and a few other directives. The first gotcha you’ll encounter is that scoped variables sometimes get shadowed.

To take a simple example, the $index property of an outer repeat directive is shadowed by the inner repeat directive. Thus:

<div ng-repeat="element in array">
    <div ng-repeat="property in element.properties>{{$index}}</div>
</div>

will produce

<div>
    <div>0</div>
    <div>1</div>
    ...
</div>
<div>
    <div>0</div>
    <div>1</div>
    ...
</div>

but you can refer to the parent scope by using the $parent property, like so:

<div ng-repeat="element in array">
    <div ng-repeat="property in element.properties>{{$parent.$index}}</div>
</div>

which will produce

<div>
    <div>0</div>
    <div>0</div>
    ...
</div>
<div>
    <div>1</div>
    <div>1</div>
    ...
</div>

(Aside: I had some trouble with inheriting extended $scopes, which I was going to address here as well, but it seems to have been cleared up in 1.0.1)

Communicate between controllers

Direct communication between controllers is frowned upon in Angular. But by creating a service which is then injected into your controllers, you can generate events that pass messages between controllers:

angular.module("myApp", [], function($provide) {
    $provide.factory('ControllerCommunicator', ['$rootScope', function($rootScope) {
        return {
            broadcast: function(event, msg) {
                $rootScope.$broadcast(event, msg);
            }
        };
     }]);
}); 

function FirstCtrl(ControllerCommunicator, $scope) {
    ControllerCommunicator.broadcast("firedEvent", {data: "message");
} 

function SecondCtrl($scope) {
    $scope.$on("firedEvent", function(event, args) {
        alert("SecondCtrl received " + args.data);
    });
}

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *