1

I have read several SO responses regarding Angular $scope and how it's a plain old JavaScript object, which means that it'll follow JS's prototypal inheritance (What are the nuances of scope prototypal / prototypical inheritance in AngularJS?)

Since this is the case, I'm curious why my following example DOESN'T throw an error:

<!doctype html>
<html ng-app='MyApp'>
<head>
  <meta charset='utf-8'>
  <title>Egghead</title>
  <script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js'></script>
  <script>
    var app = angular.module('MyApp', []);
    app.controller('MainCtrl', ['$scope', function ($scope) {

    }])
  </script>
</head>
<body>
  <div ng-controller='MainCtrl'>
    <input type='text' ng-model='data.message'>
    <p>{{ data.message }}</p>
  </div>
</body>
</html>

Based on prototypal inheritance, here's what I would expect to happen:

  1. When MainCtrl is invoked, it will create a $scope object for the MainCtrl and its corresponding view.
  2. Whenever you type into the input box, it will bind some string to $scope.data.message.
  3. However, in order to do this, the first step in JavaScript will be to try to resolve $scope.data.
  4. Since the MainCtrl function doesn't have a data property, it will try to look for the data property in the rootScope.
  5. Since the rootScope doesn't have a data property, $scope.data should resolve to 'undefined'.
  6. Finally, if you try to assign to undefined.message, this should throw an error.

However, the code happily works and data is bound correctly. Can someone help untangle why this isn't throwing an error for me?

Community
  • 1
  • 1
wmock
  • 5,382
  • 4
  • 40
  • 62
  • 1
    Leaving this as a comment because I'm sure there is a more technical response. From what I've read, you're correct up until the point of throwing the error. Instead of trying to assign to undefined.message and throwing the error, angular detects that it's undefined and creates that on the scope, then assigns the value. – Tyler McGinnis Apr 21 '14 at 02:49

2 Answers2

1

Made my original comment because I wasn't 100%, but after checking the docs, it's because...

"ngModel will try to bind to the property given by evaluating the expression on the current scope. If the property doesn't already exist on this scope, it will be created implicitly and added to the scope."

So if that property doesn't exist, it will create when then assign the value to it.

src: here

Tyler McGinnis
  • 34,836
  • 16
  • 72
  • 77
  • Thanks for pointing me back to the docs! This explains it but then the follow up question I have is whether the 'data' property will be assigned to the MainCtrl's $scope object or the rootScope object. The reason I'm not sure is because it seems like Angular is walking up the scope chain and the last scope object it deals with seems to be the rootScope object. – wmock Apr 21 '14 at 02:58
  • 1
    The data will be bound to the scope of the controller you're in, so in this example MainCtrl. I say that because the docs say 'by evaluating the expression on the CURRENT SCOPE' it then goes on to say 'if the property doesn't already exist on THIS scope' so this is referring to the current scope which is not $rootScope but the mainCtrl scope. – Tyler McGinnis Apr 21 '14 at 03:00
0

The reason why it does not fail and I mean ngModel it is because it a two way data-binding directive. You can read more about this on this other post:

What's the difference between ng-model and ng-bind

But the simpler way to explain this behavior is that if a variable is used within ngModel you are also declaring it as part of the scope even if it does not exists.

Community
  • 1
  • 1
Dalorzo
  • 19,834
  • 7
  • 55
  • 102