rchawdry
rchawdry

Reputation: 1266

AngularJS beginner data binding confusion

I'm in the middle of trying to get my head around the data binding capabilities of AngularJS and have sort of a newbie question:

In the sample below, when I type a name into the textbox, the greeting doesn't update.

<html ng-app>
<head>
    <script src="js/angular.js"></script>
    <script>
        function myCtl($scope){
            $scope.person=$scope.fname;
        }
    </script>
</head>
<body>
        <div ng-controller="myCtl">
            <input ng-model="fname"/>
            <br/>               
            Hello, {{person}}
        </div>
</body>

When I change

Hello, {{person}}

to

Hello, {{fname}}

The greeting updates as I type. I'm confused about why the second syntax works but not the first.

Upvotes: 2

Views: 942

Answers (3)

Mark Rajcok
Mark Rajcok

Reputation: 364727

$scope.person=$scope.fname creates a person primitive property on the $scope object and assigns it the value undefined (because $scope.fname does not yet exist when this line of code is executed). This is what your $scope looks like before you type into the textbox:

$scope before typing

After you type something into the textbox, Angular automatically creates a fname primitive property on the $scope, and automatic two-way databinding continually sets the value to whatever is in the textbox. So, if I type "Mark", then $scope now looks like this:

$scope after typing

It should be clear now why {{person}} shows nothing, but {{fname}} shows what is in the textbox.

Upvotes: 4

Marc
Marc

Reputation: 14361

To asgoth's answer I would also add that this code belies a misunderstanding:

$scope.person=$scope.fname;

This code is not run each time something happens in the view but only once when your controller is executed. You seem to be trying to set $scope.person to the value in $scope.fname. But $scope.fname is not defined - that's what your controller needs to do. Your view and controller are therefore both referencing an undefined value.

In a simple case like this your controller should just initialize your model when it starts:

function myCtl($scope){
    scope.person = {
        fname: '',
        lname: '',
        email: ''
    };
}

and you then bind elements to properties of person (e.g. ng-model="person.fname").

Now, whenever code runs in your controller, it automatically has the correct person.fname angular takes care of that for you - you never need to "read from your view".

function myCtl($scope){
    $scope.person = {
        fname: '',
        lname: '',
        email: ''
    };
    function validate() {
        if (!$scope.email.match(/@/) return window.alert('Please enter a valid email address!');
    }
}

From your view you would then do:

<form ng-submit="validate()">

or

<button ng-click="validate()">

Upvotes: 2

asgoth
asgoth

Reputation: 35829

Because, when you are typing in the input field, $scope.fname is changing, not $scope.person.

You could fix it with a $watch on fname:

$scope.$watch('fname', function(value) {
   if(value) {
      $scope.person = value;
   }
}, true);

Upvotes: 2

Related Questions