Search code examples
angularjsng-switchangular-ngmodel

AngularJS: ngModel with ngSwitch, cannot watch?


I'm trying to make a very simple signup form, which is supposed to work in 2 steps.

  • I ask the user for his email in the first step
  • in the second step, I ask the user for the other details (step == 2).

The template is simple;

<div class="input-group layout-container" ng-switch on="step">
    <!-- Login -->
    <img src="images/yeoman.png">
    <p>{{msg}}</p>
    <form name="signup">
        <input type="text" class="form-control login" placeholder="firstname" ng-model="firstname" ng-switch-when="2">
        <input type="text" class="form-control login" placeholder="lastname"ng-model="lastname" ng-switch-when="2">
        <input type="email" class="form-control login" placeholder="email" ng-model="email" ng-switch-when="1" required>
        <span class="error" ng-show="signup.input.$error.required">Cannot be blank</span>
        <span class="error" ng-show="signup.input.$error.email">Not a valid email</span>
        <input type="password" class="form-control login" placeholder="password" ng-model="pass" ng-switch-when="2"> <br/><br/>
        <div class="btn-container">
            <button class="btn btn-primary" ng-click="next()">Next</button>
        </div>
    </form>
</div>

As you can see, there's some basic validation going on as well, and I assign the value of the email to a model I call email.

And the controller goes like this:

.controller('SignupCtrl', function ($scope) {
    $scope.msg = "First, your email";
    $scope.step = 1;
    $scope.email = ''; // this still doesn't help
    $scope.$watch('email', function (now, then, scope) {
        console.log('email change', now, then);
    });
    $scope.next = function () {
        $scope.step = Math.min($scope.step + 1, 2);
    };
})

The problem is this: the $watch on 'email' doesn't ever trigger at all. Where's this going wrong?


Solution

  • Here is a working jsfiddle (of just the part you have a problem with): demo

    function ctrl($scope) {
        $scope.items = ['one','two'];
        $scope.selection = 'two';
        $scope.data = {email:''};
        $scope.$watch('data.email', function (now, then, scope) {
            console.log('email change', now, then);
        });
    }
    

    Note that it will only trigger the watch if the email is valid if the input is type="email".

    Edit: updated for use with ng-switch.

    Explanation: As noted by miqid, when you use primitives, child scopes have no access to parent scope variables, but when they're objects angular creates a reference in the child scopes.