Claudio Ribeiro Cláudio Ribeiro is a software developer, traveler, and writer from Lisbon. When he is not developing some cool feature at Kununu he is probably backpacking somewhere in the world or messing with some obscure framework.

A quick guide to Angular scopes

4 min read 1148

Angular applications normally rely on controllers to control the flow of data in an application. This data is then passed into a view to being rendered. To join the controller and view together Angular uses a special object called scope. This scope object acts as an execution context for expressions and is arranged hierarchically mimicking the DOM structure.

During template linking phase the directives setup $watch expressions on the scope. Those allow the directives to be notified whenever there are property changes. This way, the directive can render the updated value to the DOM.

Both controllers and directives have access to the scope, but not to each other. Now the scope ensures proper encapsulation of the controllers from the directives and the DOM.

See the Pen
I love LogRocket!
by Claudio (@DailyMatters)
on CodePen.

As we can see in the example, a controller can either write data into the scope or assign a behavior to it.

It starts by assigning LogRocket to the initial property of the scope. And then assigning the sayIlove() behavior to the Love! button. The sayIlove() method can read the initial property and create a token property. With this example, we can see that the properties on the scope can update automatically when they’re bound to HTML input widgets.

When we’re finally rendering {{token}} we’re actually:

  • Retrieving the scope associated with the DOM node where {{token}} is defined and
  • Evaluating the token expression against the scope retrieved above, and assigning the result to the text of the enclosing DOM element.

All in all, in a very simplistic manner, the scope can be seen as nothing more than the data which is used to render the view.

Scope hierarchy

Each Angular application has a root scope and can have any number of child scopes. The root scope is created whenever the Angular application is created, but then, directives cam create new child scopes. When a new child scope is created it is added as a child of his parent scope. This tree of child scopes normally parallels the DOM where they’re attached.

A perfect example of this effect in action is the one of a dynamically generated list. Each element of the list is fetched whatever source by the controller and then a new scope is created for each element. This new scope is then passed to the view, where it will be bound to a newly created DOM element. Just as we can see in the next example:

See the Pen
Scope Hierarchies
by Claudio (@DailyMatters)
on CodePen.

A quick scope hierarchies example.

 

A common DOM tree, check the ng-scope in all elements.

If we take a close look at the DOM tree, we can see that Angular adds the ng-scope to all elements where scopes are attached. All these child scopes are necessary because depending on which scope the expression is evaluated it produces a different result.

The $scope data property is attached to the DOM, and as so, it can be retrieved for debugging purposes. To examine a particular scope in the debugger we can use the built-in debugger of the browser. There are essentially three steps for this:

  • Right-click the element of interest in the browser and select the Inspect element option. This will open up the debug window with the clicked element highlighted.
  • Select the Console option if it is not already selected. The debugger allows us to access the currently selected element in the console with the $0 variable.
  • To retrieve the scope associated with the current element execute the angular.element($0).scope() command.
Debugging a scope object.

Scope event propagation

Similarly to DOM events, scopes can also propagate events. The event can be broadcasted to the scope children or emitted to scope parents. The following example shows how this can be done.

See the Pen
Angular scope event propagation
by Claudio (@DailyMatters)
on CodePen.

Angular scope propagation in action.

The $emit function is used to propagate events upwards through the scope hierarchy. As we can see in the example when the ‘emit’ button is clicked an event is propagated to the upper scope layer, which means the root scope.

The $broadcast function is propagated events downwards to every child scopes and their children scopes. In our example, when the ‘broadcast’ button is clicked, an event is propagated to the lower scope layers, which means the child and second child scopes.

Scope lifecycle

Before we wrap up, let’s talk about the scope lifecycle.

Angular uses something we can call the $digest — $apply loop to handle the lifecycle of events.

Angular by itself is unaware of model modifications. This happens because when the browser calls into Javascript, the code runs outside the Angular execution context. To enter the Angular execution context, the $apply method needs to be called. This call to $apply will evaluate the expression passed to it and then perform a ‘$digest’.

$digest is an internal cycle that runs through the application and executes $watch expressions and compares the value returned with the previous value already in the scope. If the values don’t match, a listener is fired. This cycle will run until there are no more listeners to be fired.

For example, an assignment like $scope.company=LogRocket will not trigger a $watch immediately. This is the $digest responsibility, which may or may not trigger a $watch, depending on the value that’s already on $scope.company.

This effect is beneficial for Angular performance as it consolidates all model updates into one single $watch notification. It also assures that we don’t get to inconsistent states as only one $watch notification can be running at a given time. For additional model modifications, a new $digest cycle must be triggered.

Conclusion

On this article, we spoke about Angular scopes and how they are a vital part of an Angular application. We looked scope hierarchies and events and touched base on scope lifecycle.

I hope this article was able to get you up and running with Angular Scopes and to better understand how important they are in every Angular application.


Plug: LogRocket, a DVR for web apps

https://logrocket.com/signup/

LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single page apps.

Try it for free.

Claudio Ribeiro Cláudio Ribeiro is a software developer, traveler, and writer from Lisbon. When he is not developing some cool feature at Kununu he is probably backpacking somewhere in the world or messing with some obscure framework.

Leave a Reply